Fabric自動化部署的實踐

介紹

Fabric是基于Python(2.7,3.4+以上版本)實現的SSH命令行工具卵凑,簡化了SSH的應用程序部署及系統(tǒng)管理任務所踊,它提供了系統(tǒng)基礎的操作組件箫措,可以實現本地或遠程shell命令,包括命令執(zhí)行垫桂、文件上傳鲜戒、下載及完整執(zhí)行日志輸出等功能专控。Fabric在paramiko的基礎上做了更高一層的封裝,操作起來會更加簡單遏餐。

安裝

  • python2版本:pip install fabric
  • python3版本:pip install fabric3

參數介紹

fab作為Fabric程序的命令行入口踩官,提供了豐富的參數調用,命令格式如下:
fab [options] <command>[:arg1,arg2-val2,host=foo,host='h1;h2'...]...
常用參數介紹:

  • -l:顯示定義好的任務函數名;
  • -f:指定fab入口文件境输,默認入口文件名為fabfile.py;
  • -g:指定網關(中轉)設備蔗牡,比如堡壘機環(huán)境,填寫堡壘機IP即可嗅剖;
  • -H:指定目標主機辩越,多態(tài)主機用","號分隔;
  • -P:以異步并行方式運行多主機任務信粮,默認為串行運行黔攒;
  • -R:指定role(角色),以角色名區(qū)分不同業(yè)務組設備强缘;
  • -t:設置設備連接超時時間(秒)督惰;
  • -T:設置遠程主機命令執(zhí)行超時時間(秒);
  • -w:當命令執(zhí)行失敗旅掂,發(fā)出警告赏胚,而非默認中止任務。

全部參數如下:

Options:
  -h, --help            show this help message and exit
  -d NAME, --display=NAME
                        print detailed info about command NAME
  -F FORMAT, --list-format=FORMAT
                        formats --list, choices: short, normal, nested
  -I, --initial-password-prompt
                        Force password prompt up-front
  --initial-sudo-password-prompt
                        Force sudo password prompt up-front
  -l, --list            print list of possible commands and exit
  --set=KEY=VALUE,...   comma separated KEY=VALUE pairs to set Fab env vars
  --shortlist           alias for -F short --list
  -V, --version         show program's version number and exit
  -a, --no_agent        don't use the running SSH agent
  -A, --forward-agent   forward local agent to remote end
  --abort-on-prompts    abort instead of prompting (for password, host, etc)
  -c PATH, --config=PATH
                        specify location of config file to use
  --colorize-errors     Color error output
  -D, --disable-known-hosts
                        do not load user known_hosts file
  -e, --eagerly-disconnect
                        disconnect from hosts as soon as possible
  -f PATH, --fabfile=PATH
                        python module file to import, e.g. '../other.py'
  -g HOST, --gateway=HOST
                        gateway host to connect through
  --gss-auth            Use GSS-API authentication
  --gss-deleg           Delegate GSS-API client credentials or not
  --gss-kex             Perform GSS-API Key Exchange and user authentication
  --hide=LEVELS         comma-separated list of output levels to hide
  -H HOSTS, --hosts=HOSTS
                        comma-separated list of hosts to operate on
  -i PATH               path to SSH private key file. May be repeated.
  -k, --no-keys         don't load private key files from ~/.ssh/
  --keepalive=N         enables a keepalive every N seconds
  --linewise            print line-by-line instead of byte-by-byte
  -n M, --connection-attempts=M
                        make M attempts to connect before giving up
  --no-pty              do not use pseudo-terminal in run/sudo
  -p PASSWORD, --password=PASSWORD
                        password for use with authentication and/or sudo
  -P, --parallel        default to parallel execution method
  --port=PORT           SSH connection port
  -r, --reject-unknown-hosts
                        reject unknown hosts
  --sudo-password=SUDO_PASSWORD
                        password for use with sudo only
  --system-known-hosts=SYSTEM_KNOWN_HOSTS
                        load system known_hosts file before reading user
                        known_hosts
  -R ROLES, --roles=ROLES
                        comma-separated list of roles to operate on
  -s SHELL, --shell=SHELL
                        specify a new shell, defaults to '/bin/bash -l -c'
  --show=LEVELS         comma-separated list of output levels to show
  --skip-bad-hosts      skip over hosts that can't be reached
  --skip-unknown-tasks  skip over unknown tasks
  --ssh-config-path=PATH
                        Path to SSH config file
  -t N, --timeout=N     set connection timeout to N seconds
  -T N, --command-timeout=N
                        set remote command timeout to N seconds
  -u USER, --user=USER  username to use when connecting to remote hosts
  -w, --warn-only       warn, instead of abort, when commands fail
  -x HOSTS, --exclude-hosts=HOSTS
                        comma-separated list of hosts to exclude
  -z INT, --pool-size=INT
                        number of concurrent processes to use in parallel mode

編寫方式

全局屬性

env對象的作用是定義fabfile的全局設定商虐,支持多個屬性觉阅,包含目標主機、用戶名秘车、密碼典勇、等角色,各屬性說明如下:

  • evn.host:定義目標主機叮趴,可以用IP或主機名表示割笙,以Python的列表形式定義,如evn.hosts['192.168.56.133','192.168.56.134']眯亦。
  • env.exclude_hosts:排除指定主機伤溉,如env.exclude_hosts=['192.168.56.133']豪嚎。
  • env.user:定義用戶名,如env.user="root"谈火。
  • env.port:定義目標主機端口,默認為22舌涨,如env.port="22"糯耍。
  • env.password:定義密碼,如env.password='1234567'囊嘉。
  • env.passwords:與password功能一樣温技,區(qū)別在于不同主機不同密碼的應用場景,需要注意的是扭粱,配置passwords是需配置用戶舵鳞、主機、端口等信息琢蛤,如下方式:
env.passwords = {
    'root@192.168.56.131:22':'1234567',
    'root@192.168.56.132:22':'1234567',
    'root@192.168.56.133:22':'1234567',
    'root@192.168.56.134:22':'1234567'
}
  • env.gateway:定義網關(中轉蜓堕、堡壘機)IP,如env.gateway = '192.168.56.1'博其。
  • env.deploy_release_dir:自定義全局變量套才,格式:env.+"變量名稱",如env.deploy_release_dir慕淡、env.age背伴、env.sex等。
    ( env.roledefs:定義角色分組峰髓,比如web組與db組主機區(qū)分開來傻寂,定義如下:
env.roledefs = {
    'webservers':['192.168.56.131','192.168.56.132','192.168.56.133'],
    'dbserver':['192.168.56.134','192.168.56.135']
}
不同角色執(zhí)行不同的任務函數

引用時使用Python修飾符的形式進行,角色修飾符下面的任務函數為其作用域携兵,下面來看一個示例:

@roles('webservers')
def webtask():
    run('/etc/init.d/nginx start')

@roles('dbservers')
def dbtask():
    run('/etc/init.d/mysql start')

@roles('webservers','dbservers')
def pubclitasj():
    run('uptime')

def deploy():
    execute(webtask)
    execute(dbtask)
    execute(pubclitask)

常用API

Fabric提供了一組簡單但功能強大的fabric.api命令集疾掰,簡單地調用這些API就能完成大部分應用場景需求。Fabric常用方法及說明如下:

  • local:執(zhí)行本地命令徐紧,如:local('uname -s');
  • lcd:切換本地目錄个绍,如:lcd('/home');
  • cd:切換遠程目錄浪汪,如:cd('/data/logs')巴柿;
  • run:執(zhí)行遠程命令,如:run('free -m')死遭;
  • sudo:sudo方式執(zhí)行遠程命令广恢,如:sudo('/etc/init.d/httpd start');
  • put:上傳本地文件到遠程主機呀潭,如:put('/home/user.info','/data/user.info');
  • prompt:獲得用戶輸入信息钉迷,如:prompt('please input user password:')至非;
  • confirm:獲得提示信息確認,如:confirm("Tests failed. Continue[Y/N]?")糠聪;
  • reboot:重啟遠程主機荒椭,如:reboot();
  • @task:函數修飾符,標識的函數為fab可調用的凭需,非標記對fab不可見税稼,純業(yè)務邏輯;
  • runs_once:函數修復符味悄,標識的函數只會執(zhí)行一次,不受多臺主機影響塌鸯。

簡單實例

查看遠程主機信息

本示例調用local()方法執(zhí)行本地(主控端)命令侍瑟,添加"@runs_once"修飾符保證該任務函數只執(zhí)行一次。調用run()方法執(zhí)行遠程命令丙猬。

  • test01.py
from fabric.api import *

env.user = 'devops'
env.hosts = ['localhost']
env.password = '1234567'

@runs_once              # 查看本地系統(tǒng)信息涨颜,當有多臺主機時只運行一次
def local_task():       # 本地任務函數
    local("uname -a")
  • 運行及結果
    fab -f simple1.py local_task
[localhost] Executing task 'local_task'
[localhost] local: uname -a
Linux devops-virtual-machine 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux

Done.
動態(tài)獲取遠程目錄列表

本示例使用"@task'修復符標志入口函數go()對外部可見,配合"@runs_once"修飾符接受用戶輸入茧球,最后調用worktask()任務函數實現遠程命令執(zhí)行咐低。

  • test02.py
from fabric.api import *

env.user = 'root'
env.hosts = ['192.168.56.11','192.168.56.12']
env.password = '1234567'

@runs_once           # 主機遍歷過程中,只有第一臺觸發(fā)此函數
def input_raw():
    return prompt("Please input directory name:",default="/home")


def worktask(dirname):
    run("ls -l "+dirname)

@task           # 限定只有go函數對fab命令可見
def go():
    getdirname = input_raw()
    worktask(getdirname)

該示例實現了一個動態(tài)輸入遠程目錄名稱袜腥,再獲取目錄列表的功能见擦,由于我們只要求輸入一次,在顯示所有主機上該目錄的列表信息羹令,調用一個子函數input_raw()同時配置@runs_once修復符來達到此目的鲤屡。

  • 運行及結果
    fab -f simple3.py go
[192.168.56.11] Executing task 'go'
Please input directory name: [/home] /root
[192.168.56.11] run: ls -l /root
[192.168.56.11] out: total 4
[192.168.56.11] out: -rw-------. 1 root root 1273 May 29 11:47 anaconda-ks.cfg
[192.168.56.11] out:

[192.168.56.12] Executing task 'go'
[192.168.56.12] run: ls -l /root
[192.168.56.12] out: total 4
[192.168.56.12] out: -rw-------. 1 root root 1273 May 29 11:59 anaconda-ks.cfg
[192.168.56.12] out:


Done.
Disconnecting from 192.168.56.11... done.
Disconnecting from 192.168.56.12... done.
網關模式文件上傳與執(zhí)行

本示例通過Fabric的env對象定義網關模式,即俗稱的中轉福侈、堡壘機環(huán)境酒来。定義格式為"env.gateway='192.168.56.11'",其中IP“192.168.56.11”為堡壘機IP,再結合任務韓素實現目標主機文件上傳與執(zhí)行的操作肪凛。

  • test03.py
from fabric.api import *
from fabric.context_managers import *
from fabric.contrib.console import confirm


env.user = 'root'
env.gateway = '192.168.56.11'                           #定義堡壘機IP堰汉,作為文件上傳、執(zhí)行的中轉設備
env.hosts = ['192.168.56.12','192.168.56.13']

env.passwords = {
    'root@192.168.56.11:22':'1234567',                  #堡壘機賬號信息
    'root@192.168.56.12:22':'1234567',
    'root@192.168.56.13:22':'1234567'
}

l_pack_path = "/home/install/nginx-1.6.3.tar.gz"        #本地安裝包路徑
r_pack_path = "/tmp/install"                            #遠程安裝包路徑


@task
def put_task():
    run("mkdir -p /tmp/install")
    with settings(warn_only=True):
        result = put(l_pack_path,r_pack_path)          #上傳安裝包
    if result.failed and not confirm("put file failed, Continue[Y/N]?"):
        abort("Aborint file put task!")


@task
def run_task():                    #執(zhí)行遠程命令伟墙,安裝nginx
    with cd(r_pack_path):
        run("tar -xvf nginx-1.6.3.tar.gz")
        with cd("nginx-1.6.3/"):                     #使用with繼續(xù)繼承/tmp/install目錄位置狀態(tài)
            run("./nginx_install.sh")

@task
def go():       #上傳翘鸭、安裝
    put_task()
    run_task()
  • 運行及結果
    fab -f simple4.py go
    運行結果如下:
devops@devops-virtual-machine:~/devops$ fab -f simple4.py go
[192.168.56.12] Executing task 'go'
[192.168.56.12] run: mkdir -p /tmp/install
[192.168.56.12] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.12] run: tar -xvf nginx-1.6.3.tar.gz
.....
.....
.....
[192.168.56.12] out: cp conf/nginx.conf '/usr/local/nginx/conf/nginx.conf.default'
[192.168.56.12] out: test -d '/usr/local/nginx/logs'         || mkdir -p '/usr/local/nginx/logs'
[192.168.56.12] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.12] out: test -d '/usr/local/nginx/html'         || cp -R html '/usr/local/nginx'
[192.168.56.12] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.12] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.12] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.12] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.12] out:

[192.168.56.13] Executing task 'go'
[192.168.56.13] run: mkdir -p /tmp/install
[192.168.56.13] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.13] run: tar -xvf nginx-1.6.3.tar.gz
....
....
....
[192.168.56.13] out: cp conf/nginx.conf '/usr/local/nginx/conf/nginx.conf.default'
[192.168.56.13] out: test -d '/usr/local/nginx/logs'         || mkdir -p '/usr/local/nginx/logs'
[192.168.56.13] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.13] out: test -d '/usr/local/nginx/html'         || cp -R html '/usr/local/nginx'
[192.168.56.13] out: test -d '/usr/local/nginx/logs' ||         mkdir -p '/usr/local/nginx/logs'
[192.168.56.13] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.13] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.13] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.13] out:


Done.
Disconnecting from 192.168.56.11... done.
Disconnecting from 192.168.56.12... done.
Disconnecting from 192.168.56.13... done.

fab -Pf simple4.py go
運行結果如下:

devops@devops-virtual-machine:~/devops$ fab -Pf simple4.py go
[192.168.56.12] Executing task 'go'
[192.168.56.13] Executing task 'go'
[192.168.56.12] run: mkdir -p /tmp/install
[192.168.56.13] run: mkdir -p /tmp/install
[192.168.56.12] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.13] put: /home/install/nginx-1.6.3.tar.gz -> /tmp/install/nginx-1.6.3.tar.gz
[192.168.56.12] run: tar -xvf nginx-1.6.3.tar.gz
....
....
....
[192.168.56.12] out: nginx-1.6.3/html/index.html
[192.168.56.12] out: nginx-1.6.3/README
[192.168.56.12] out: nginx-1.6.3/nginx_install.sh
[192.168.56.12] out: nginx-1.6.3/configure
[192.168.56.12] out:

[192.168.56.12] run: ./nginx_install.sh
[192.168.56.13] run: tar -xvf nginx-1.6.3.tar.gz
[192.168.56.13] out: nginx-1.6.3/
[192.168.56.13] out: nginx-1.6.3/src/
....
....
....
[192.168.56.12] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.12] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.12] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.12] out:
....
....
...
[192.168.56.13] out: make[1]: Leaving directory `/tmp/install/nginx-1.6.3'
[192.168.56.13] out: nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
[192.168.56.13] out: nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[192.168.56.13] out:

文件打包、上傳與校驗

我們時常做一些文件包分發(fā)的工作戳葵,實施步驟一般是先壓縮打包就乓,在批量上傳至目標服務器,最后做一致性校驗。本示例通過put()方法實現文件的上傳生蚁,通過對比本地與遠程主機文件的md5噩翠,最終實現文件一致性校驗。

  • simple5.py
from fabric.api import *
from fabric.context_managers import *
from fabric.contrib.console import confirm

env.user = 'root'
env.hosts = ['192.168.56.12','192.168.56.13']
env.passwords = {
    'root@192.168.56.12:22':'1234567',
    'root@192.168.56.13:22':'1234567',
}

@runs_once
def tar_task():             #本地打包任務函數邦投,只執(zhí)行一次
    with lcd('/home/devops/devops'):
        local("tar -zcf devops.tar.gz  *")

@task
def put_task():                 #上傳文件任務函數
    run("mkdir -p /root/devops")
    with cd("/root/devops"):
        with settings(warn_only=True):                  #put(上傳)出現異常時繼續(xù)執(zhí)行伤锚,非終止
            result = put("/home/devops/devops/devops.tar.gz","/root/devops/devops.tar.gz")
        if result.failed and not confirm("put file failed.Continue[Y/N]?"):
            abort("Aborting file put task!")                        #出現異常時,確認用戶是否繼續(xù)志衣,(Y繼續(xù))


@task
def check_task():               #校驗文件任務函數
    with settings(warn_only=True):
        #本地local命令需要配置capture=True才能捕獲返回值
        lmd5 = local("md5sum /home/devops/devops/devops.tar.gz",capture=True).split(' ')[0]
        rmd5 = run("md5sum /root/devops/devops.tar.gz").split(' ')[0]
    if lmd5 == rmd5:                #對比本地及遠程文件md5信息
        prompt("OK")
    else:
        prompt("ERROR")

@task
def go():
    tar_task()
    put_task()
    check_task()
  • 運行及結果
    fab -f simple5.py go
    運行結果如下:(提示此程序不支持-P參數并行執(zhí)行屯援、如需并行執(zhí)行,程序需要做調整)
devops@devops-virtual-machine:~/devops$ fab -f simple5.py go
[192.168.56.12] Executing task 'go'
[localhost] local: tar -zcf devops.tar.gz  *
[192.168.56.12] run: mkdir -p /root/devops
[192.168.56.12] put: /home/devops/devops/devops.tar.gz -> /root/devops/devops.tar.gz
[localhost] local: md5sum /home/devops/devops/devops.tar.gz
[192.168.56.12] run: md5sum /root/devops/devops.tar.gz
[192.168.56.12] out: a1cf2be82647cbed0d41514bd80373de  /root/devops/devops.tar.gz
[192.168.56.12] out:

OK
[192.168.56.13] Executing task 'go'
[192.168.56.13] run: mkdir -p /root/devops
[192.168.56.13] put: /home/devops/devops/devops.tar.gz -> /root/devops/devops.tar.gz
[localhost] local: md5sum /home/devops/devops/devops.tar.gz
[192.168.56.13] run: md5sum /root/devops/devops.tar.gz
[192.168.56.13] out: a1cf2be82647cbed0d41514bd80373de  /root/devops/devops.tar.gz
[192.168.56.13] out:

OK

Done.
Disconnecting from 192.168.56.12... done.
Disconnecting from 192.168.56.13... done.

部署LNMP業(yè)務服務環(huán)境

本示例通過env.roledefs定義不同主機角色蠢涝,在使用"@roles('webservers')"修復符綁定到對應的任務函數,實現不同角色主機的部署差異阅懦。

  • simple6.py
from fabric.colors import *
from fabric.api import *

env.user = 'root'
env.roledefs = {
    'webservers':['192.168.56.11','192.168.56.12'],
    'dbservers':['192.168.56.13']
}

env.passwords = {
    'root@192.168.56.11:22':'1234567',
    'root@192.168.56.12:22':'1234567',
    'root@192.168.56.13:22':'1234567',
}

@roles('webservers')                      #使用webtask任務函數引用'webservers'角色修復符
def webtask():
    print(yellow('Install nginx php php-fpm...'))
    with settings(warn_only=True):
        run("yum -y install nginx")
        run("yum -y install php-fpm php-mysql php-mbstring php-xml php-mcrypt php-gd")
        run("chkconfig --levels 235 php-fpm on")
        run("chkconfig --levels 235 nginx on")

@roles('dbservers')                       #dbtask任務函數引用'dbservers'角色修復符
def dbtask():
    print(yellow("Install Mysql..."))
    with settings(warn_only=True):
        run("yum -y install mysql mysql-server")
        run("chkconfig --levels 235 mysqld on")

@roles('webservers','dbservers')           #publictask任務函數同時引用兩個角色修復符
def publictask():                          #部署公共類環(huán)境和二,如epel、ntp等
    print(yellow("Install epel ntp...."))
    with settings(warn_only=True):
        run("wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo")
        run("yum -y install ntp")

def deploy():
    execute(publictask)
    execute(webtask)
    execute(dbtask)
  • 運行及結果
    fab -Pf simple6.py deploy
    執(zhí)行結果如下所示:
devops@devops-virtual-machine:~/devops$ fab -Pf simple6.py deploy
[192.168.56.11] Executing task 'publictask'
[192.168.56.12] Executing task 'publictask'
[192.168.56.13] Executing task 'publictask'
Install epel ntp....
[192.168.56.13] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
Install epel ntp....
[192.168.56.12] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
Install epel ntp....
[192.168.56.11] run: wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.12] out: --2018-06-23 20:32:30--  http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.11] out: --2018-06-23 20:32:30--  http://mirrors.aliyun.com/repo/epel-7.repo
[192.168.56.13] out: --2018-06-23 20:32:30--  http://mirrors.aliyun.com/repo/epel-7.repo
....
[192.168.56.13] run: yum -y install ntp
[192.168.56.12] run: yum -y install ntp
[192.168.56.11] run: yum -y install ntp
....
....
....
[192.168.56.11] Executing task 'webtask'
[192.168.56.12] Executing task 'webtask'
Install nginx php php-fpm...
[192.168.56.11] run: yum -y install nginx
Install nginx php php-fpm...
[192.168.56.12] run: yum -y install nginx
....
....
....
[192.168.56.13] Executing task 'dbtask'
Install Mysql...
[192.168.56.13] run: rpm -ivh http://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
.....
.....
.....
[192.168.56.13] run: chkconfig --levels 235 mysqld on

Done.

生產環(huán)境代碼包發(fā)布管理

程序生產環(huán)境的發(fā)布是業(yè)務上線的最后一個環(huán)境耳胎,要求具備源碼打包惯吕、發(fā)布、切換怕午、回滾废登、版本管理等功能。本示例實現了這一套流程功能郁惜,其中版本切換與回滾使用了Linux下的軟鏈接實現堡距。

  • pro.py
from fabric.api import *
from fabric.colors import *
from fabric.context_managers import *
from fabric.contrib.console import confirm
import time

env.user = 'root'
env.host = ['192.168.56.12','192.168.56.13']
env.passwords = {
    'root@192.168.56.12:22':'1234567',
    'root@192.168.56.13:22':'1234567',
}

env.project_dev_source = '/data/dev/Lwebadmin/'              #開發(fā)服務器項目主目錄
env.project_tar_source = '/data/dev/releases/'               #開發(fā)服務器項目壓縮包存儲目錄
env.project_pack_name = 'release'                            #項目壓縮包前綴,文件名為release.tar.gz

env.deploy_project_root = '/data/www/Lwebadmin/'            #項目生產環(huán)境主目錄
env.deploy_release_dir = 'releases'                         #項目發(fā)布目錄兆蕉,位于主目錄下面
env.deploy_current_dir = 'current'                          #對外服務的當前版本軟鏈接
env.deploy_version = time.strftime("%Y%m%d")+"v2"           #版本號

@runs_once
def input_versionid():                                      #獲得用戶輸入的版本號羽戒,以便做版本回滾操作
    return prompt("Please input project rollback version ID:",default="")

@task
@runs_once
def tar_source():                                           #打包本地項目主目錄,并將壓縮包存儲到本地壓縮包目錄
    prompt(yellow("Creating source package...."))
    with lcd(env.project_dev_source):
        local("tar -zcf %s.tar.gz ." %(env.project_tar_source + env.project_pack_name))
    prompt(green("Creating source package success!"))

@task
def put_package():                                          #上傳任務函數
    prompt(yellow("Start put package...."))
    with settings(warn_only=True):
        with cd(env.deploy_project_root + env.deploy_release_dir):
            run("mkdir %s" %(env.deploy_version))           #創(chuàng)建版本目錄
    env.deploy_full_path = env.deploy_project_root + env.deploy_release_dir + "/" + env.deploy_version
    with settings(warn_only=True):                          #上傳項目壓縮包至此目錄
        result = put(env.project_tar_source + env.project_pack_name + ".tar.gz",env.deploy_full_path)
    if result.failed and not ("put file failed,Continue[Y/N]?"):
        abort("Aborting file put task!")

    with cd(env.deploy_full_path):                          #成功解壓后刪除壓縮包
        run("tar -zxvf %s.tar.gz" %(env.project_pack_name))
        run("rm -rf %s.tar.gz" %(env.project_pack_name))

    print(green("Put & untar package success!"))

@task
def make_symlink():                                         #為當前版本目錄做軟鏈接
    print(yellow("update current symlink"))
    env.deploy_full_path = env.deploy_project_root + env.deploy_release_dir + "/" + env.deploy_version
    with settings(warn_only=True):                           #刪除軟鏈接虎韵,重新創(chuàng)建并指定軟鏈接源目錄易稠,新版本生效
        run("rm -rf %s" %(env.deploy_project_root + env.deploy_current_dir))
        run("ln -s %s %s" %(env.deploy_full_path,env.deploy_project_root + env.deploy_current_dir))
    print(green("make symlink success!"))

@task
def rollback():                                             #版本回滾任務函數
    print(yellow("rollback project version"))
    versionid = input_versionid()                           #獲取用戶輸入的回滾版本號
    if versionid == '':
        abort("Project version ID error,abort!")

    env.deploy_full_path = env.deploy_project_root + env.deploy_release_dir + "/" + versionid
    run("rm -r %s" %(env.deploy_project_root + env.deploy_current_dir))
    run("ln -s %s %s" %(env.deploy_full_path,env.deploy_project_root + env.deploy_current_dir))     #刪除軟鏈接,重新創(chuàng)建并指定軟鏈接源目錄包蓝,新版本生效
    print(green("rollback sucess!"))


@task
def go():               #自動化程序版本發(fā)布入口函數
    tar_source()
    put_package()
    make_symlink()

在生產環(huán)境中將站點的根目錄指向"/data/www/Lwebadmin/current",由于使用Linux軟鏈接做切換驶社,管理員的版本發(fā)布、回滾操作用戶無感知测萎。


轉載自:https://www.cnblogs.com/hwlong/p/9216492.html

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末亡电,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子硅瞧,更是在濱河造成了極大的恐慌逊抡,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異冒嫡,居然都是意外死亡拇勃,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門孝凌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來方咆,“玉大人,你說我怎么就攤上這事蟀架“曷福” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵片拍,是天一觀的道長煌集。 經常有香客問我,道長捌省,這世上最難降的妖魔是什么苫纤? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮纲缓,結果婚禮上卷拘,老公的妹妹穿的比我還像新娘。我一直安慰自己祝高,他們只是感情好栗弟,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著工闺,像睡著了一般乍赫。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陆蟆,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天耿焊,我揣著相機與錄音,去河邊找鬼遍搞。 笑死罗侯,一個胖子當著我的面吹牛,可吹牛的內容都是我干的溪猿。 我是一名探鬼主播钩杰,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼诊县!你這毒婦竟也來了讲弄?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤依痊,失蹤者是張志新(化名)和其女友劉穎避除,沒想到半個月后怎披,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡瓶摆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年凉逛,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片群井。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡状飞,死狀恐怖,靈堂內的尸體忽然破棺而出书斜,到底是詐尸還是另有隱情诬辈,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布荐吉,位于F島的核電站焙糟,受9級特大地震影響,放射性物質發(fā)生泄漏样屠。R本人自食惡果不足惜穿撮,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞧哟。 院中可真熱鬧混巧,春花似錦枪向、人聲如沸勤揩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陨亡。三九已至,卻和暖如春深员,著一層夾襖步出監(jiān)牢的瞬間负蠕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工倦畅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留遮糖,地道東北人。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓叠赐,卻偏偏與公主長得像欲账,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子芭概,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354