Python應用自動化部署工具Fabric原理及使用解析
介紹
Fabirc是基于python實現(xiàn)的SSH命令行工具,非常適合應用的自動化部署,或者執(zhí)行系統(tǒng)管理任務。
python2:pip3 install fabric
python3:pip3 install fabric3
簡單的例子:
root@openstack:~# cat fabfile.py def hello(): print('hello world!') root@openstack:~# fab hello hello world!
這個fab簡單地導入了fabfile,并執(zhí)行定義的hello函數(shù)。
命令行啟動
fab作為Fabric程序的命令行入口,提供了豐富的參數(shù)調(diào)用,命令格式如下:
root@openstack:~# fab --help
Usage: fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ...
各參數(shù)含義如下:
參數(shù)項 | 含義 |
---|---|
-l | 顯示可用任務函數(shù)名 |
-f | 指定fab入口文件,默認為fabfile.py |
-g | 指定網(wǎng)關(中轉(zhuǎn)設備),比如堡壘機環(huán)境,填寫堡壘機IP即可 |
-H | 指定目標主機,多臺主機用“,”分隔 |
-P | 以異步并行方式運行多臺主機任務,默認為串行運行 |
-R | 指定角色(Role) |
-t | 設置設備連接超時時間 |
-T | 設置遠程主機命令執(zhí)行超時時間 |
-w | 當命令執(zhí)行失敗,發(fā)出告警,而非默認終止任務 |
fabfile全局屬性設定
env對象的作用是定義fabfile的全局設定,各屬性說明如下:
屬性 | 含義 |
---|---|
env.host | 定義目標主機,以python的列表表示,如env.host=['xx.xx.xx.xx','xx.xx.xx.xx'] |
env.exclude_hosts | 排除指定主機,以python的列表表示 |
env.port | 定義目標主機端口,默認為22 |
env.user | 定義用戶名 |
env.password | 定義密碼 |
env.passwords | 與password功能一樣,區(qū)別在于不同主機配置不同密碼的應用情景,配置此項的時候需要配置用戶、主機、端口等信息,如:env.passwords = {'root@xx.xx.xx.xx:22': '123', 'root@xx.xx.xx.xx':'234'} |
env.getway | 定義網(wǎng)關 |
env.deploy_release_dir | 自定義全局變量 |
env.roledefs | 定義角色分組 |
常用的API
Fabric支持常用的方法及說明如下:
方法 | 說明 | |
---|---|---|
local | 執(zhí)行本地命令,如:local('hostname') | |
lcd | 切換本地目錄,lcd('/root') | |
cd | 切換遠程目錄,cd('cd') | |
run | 執(zhí)行遠程命令,如:run('hostname') | |
sudo | sudo執(zhí)行遠程命令,如:sudo('echo “123456″ | passwd --stdin root') |
put | 上傳本地文件到遠程主機,如:put(src,des) | |
get | 從遠程主機下載文件到本地,如:get(des,src) | |
prompt | 獲取用戶輸入信息,如:prompt(‘please enter a new password:') | |
confirm | 獲取提示信息確認,如:confirm('failed.Continue[Y/n]?') | |
reboot | 重啟遠程主機,reboot() | |
@task | 函數(shù)修飾符,標識的函數(shù)為fab可調(diào)用的 | |
@runs_once | 函數(shù)修飾符,表示的函數(shù)只會執(zhí)行一次 |
從一個實例入手
假設我們需要為一個 web 應用創(chuàng)建 fabfile 。具體的情景如下:這個 web 應用的代碼使用 git 托管在一臺遠程服務器 vcshost 上,我們把它的代碼庫克隆到了本地 localhost 中。我們希望在我們把修改后的代碼 push 回 vcshost 時,自動把新的版本安裝到另一臺遠程服務器 my_server 上。我們將通過自動化本地和遠程 git 命令來完成這些工作。
關于 fabfile 文件放置位置的最佳時間是項目的根目錄:
. |-- __init__.py |-- app.wsgi |-- fabfile.py <-- our fabfile! |-- manage.py `-- my_app |-- __init__.py |-- models.py |-- templates | `-- index.html |-- tests.py |-- urls.py `-- views.py
注解
在這里我們使用一個 Django 應用為例——不過 Fabric 并s依賴于外部代碼,除了它的 SSH 庫。
作為起步,我們希望先執(zhí)行測試準備好部署后,再提交到 VCS(版本控制系統(tǒng)):
from fabric.api import local def prepare_deploy(): local("./manage.py test my_app") local("git add -p && git commit") local("git push")
這段代碼的輸出會是這樣:
$ fab prepare_deploy [localhost] run: ./manage.py test my_app Creating test database... Creating tables Creating indexes .......................................... ---------------------------------------------------------------------- Ran 42 tests in 9.138s OK Destroying test database... [localhost] run: git add -p && git commit <interactive Git add / git commit edit message session> [localhost] run: git push <git push session, possibly merging conflicts interactively> Done.
這段代碼很簡單,導入一個 Fabric API: local ,然后用它執(zhí)行本地 Shell 命令并與之交互,剩下的 Fabric API 也都類似——它們都只是 Python。
用你的方式來組織
因為 Fabric “只是 Python”,所以你可以按你喜歡的方式來組織 fabfile 。比如說,把任務分割成多個子任務:
from fabric.api import local def test(): local("./manage.py test my_app") def commit(): local("git add -p && git commit") def push(): local("git push") def prepare_deploy(): test() commit() push()
這個 prepare_deploy 任務仍可以像之前那樣調(diào)用,但現(xiàn)在只要你愿意,就可以調(diào)用更細粒度的子任務。
故障
我們的基本案例已經(jīng)可以正常工作了,但如果測試失敗了會怎樣?我們應該抓住機會即使停下任務,并在部署之前修復這些失敗的測試。
Fabric 會檢查被調(diào)用程序的返回值,如果這些程序沒有干凈地退出,F(xiàn)abric 會終止操作。下面我們就來看看如果一個測試用例遇到錯誤時會發(fā)生什么:
$ fab prepare_deploy [localhost] run: ./manage.py test my_app Creating test database... Creating tables Creating indexes .............E............................ ====================================================================== ERROR: testSomething (my_project.my_app.tests.MainTests) ---------------------------------------------------------------------- Traceback (most recent call last): [...] ---------------------------------------------------------------------- Ran 42 tests in 9.138s FAILED (errors=1) Destroying test database... Fatal error: local() encountered an error (return code 2) while executing './manage.py test my_app' Aborting.
太好了!我們什么都不用做,F(xiàn)abric 檢測到了錯誤并終止,不會繼續(xù)執(zhí)行 commit 任務。
參見
Failure handling (usage documentation)
故障處理
但如果我們想更加靈活,給用戶另一個選擇,該怎么辦?一個名為 warn_only 的設置(或著說 環(huán)境變量 ,通??s寫為 env var )可以把退出換為警告,以提供更靈活的錯誤處理。
讓我們把這個設置丟到 test 函數(shù)中,然后注意這個 local 調(diào)用的結(jié)果:
from __future__ import with_statement from fabric.api import local, settings, abort from fabric.contrib.console import confirm def test(): with settings(warn_only=True): result = local('./manage.py test my_app', capture=True) if result.failed and not confirm("Tests failed. Continue anyway?"): abort("Aborting at user request.") [...]
為了引入這個新特性,我們需要添加一些新東西:
在 Python 2.5 中,需要從 __future__ 中導入 with ;
Fabric contrib.console 子模塊提供了 confirm 函數(shù),用于簡單的 yes/no 提示。
settings 上下文管理器提供了特定代碼塊特殊設置的功能。
local 這樣運行命令的操作會返回一個包含執(zhí)行結(jié)果( .failed 或 .return_code 屬性)的對象。
abort 函數(shù)用于手動停止任務的執(zhí)行。
即使增加了上述復雜度,整個處理過程仍然很容易理解,而且它已經(jīng)遠比之前靈活。
建立連接
讓我們回到 fabfile 的主旨:定義一個 deploy 任務,讓它在一臺或多臺遠程服務器上運行,并保證代碼是最新的:
def deploy():
code_dir = '/srv/django/myproject'
with cd(code_dir):
run("git pull")
run("touch app.wsgi")
這里再次引入了一些新的概念:
Fabric 是 Python——所以我們可以自由地使用變量、字符串等常規(guī)的 Python 代碼;
cd 函數(shù)是一個簡易的前綴命令,相當于運行 cd /to/some/directory ,和 lcd 函數(shù)類似,只不過后者是在本地執(zhí)行。
~fabric.operations.run` 和 local 類似,不過是在 遠程 而非本地執(zhí)行。
我們還需要保證在文件頂部導入了這些新函數(shù):
from __future__ import with_statement
from fabric.api import local, settings, abort, run, cd
from fabric.contrib.console import confirm
改好之后,我們重新部署:
$ fab deploy
No hosts found. Please specify (single) host string for connection: my_server
[my_server] run: git pull
[my_server] out: Already up-to-date.
[my_server] out:
[my_server] run: touch app.wsgiDone.
我們并沒有在 fabfile 中指定任何連接信息,所以 Fabric 依舊不知道該在哪里運行這些遠程命令。遇到這種情況時,F(xiàn)abric 會在運行時提示我們。連接的定義使用 SSH 風格的“主機串”(例如: user@host:port ),默認使用你的本地用戶名——所以在這個例子中,我們只需要指定主機名 my_server 。
與遠程交互
如果你已經(jīng)得到了代碼,說明 git pull 執(zhí)行非常順利——但如果這是第一次部署呢?最好也能應付這樣的情況,這時應該使用 git clone 來初始化代碼庫:
def deploy(): code_dir = '/srv/django/myproject' with settings(warn_only=True): if run("test -d %s" % code_dir).failed: run("git clone user@vcshost:/path/to/repo/.git %s" % code_dir) with cd(code_dir): run("git pull") run("touch app.wsgi")
和上面調(diào)用 local 一樣, run 也提供基于 Shell 命令構建干凈的 Python 邏輯。這里最有趣的部分是 git clone :因為我們是用 git 的 SSH 方法來訪問 git 服務器上的代碼庫,這意味著我們遠程執(zhí)行的 run 需要自己提供身份驗證。
舊版本的 Fabric(和其他類似的高層次 SSH 庫)像在監(jiān)獄里一樣運行遠程命令,無法提供本地交互。當你迫切需要輸入密碼或者與遠程程序交互時,這就很成問題。
Fabric 1.0 和后續(xù)的版本突破了這個限制,并保證你和另一端的會話交互。讓我們看看當我們在一臺沒有 git checkout 的新服務器上運行更新后的 deploy 任務時會發(fā)生什么:
$ fab deploy
No hosts found. Please specify (single) host string for connection: my_server
[my_server] run: test -d /srv/django/myprojectWarning: run() encountered an error (return code 1) while executing 'test -d /srv/django/myproject'
[my_server] run: git clone user@vcshost:/path/to/repo/.git /srv/django/myproject
[my_server] out: Cloning into /srv/django/myproject...
[my_server] out: Password: <enter password>
[my_server] out: remote: Counting objects: 6698, done.
[my_server] out: remote: Compressing objects: 100% (2237/2237), done.
[my_server] out: remote: Total 6698 (delta 4633), reused 6414 (delta 4412)
[my_server] out: Receiving objects: 100% (6698/6698), 1.28 MiB, done.
[my_server] out: Resolving deltas: 100% (4633/4633), done.
[my_server] out:
[my_server] run: git pull
[my_server] out: Already up-to-date.
[my_server] out:
[my_server] run: touch app.wsgiDone.
注意那個 Password: 提示——那就是我們在 web 服務器上的遠程 git 應用在請求 git 密碼。我們可以在本地輸入密碼,然后像往常一樣繼續(xù)克隆。
參見
預定義連接
在運行輸入連接信息已經(jīng)是非常古老的做法了,F(xiàn)abric 提供了一套在 fabfile 或命令行中指定服務器信息的簡單方法。這里我們不展開說明,但是會展示最常用的方法:設置全局主機列表 env.hosts 。
env 是一個全局的類字典對象,是 Fabric 很多設置的基礎,也能在 with 表達式中使用(事實上,前面見過的 ~fabric.context_managers.settings 就是它的一個簡單封裝)。因此,我們可以在模塊層次上,在 fabfile 的頂部附近修改它,就像這樣:
from __future__ import with_statement from fabric.api import * from fabric.contrib.console import confirm env.hosts = ['my_server'] def test(): do_test_stuff()
當 fab 加載 fabfile 時,將會執(zhí)行我們對 env 的修改并保存設置的變化。最終結(jié)果如上所示:我們的 deploy 任務將在 my_server 上運行。
這就是如何指定 Fabric 一次性控制多臺遠程服務器的方法: env.hosts 是一個列表, fab 對它迭代,對每個連接運行指定的任務。
總結(jié)
雖然經(jīng)歷了很多,我們的 fabfile 文件仍然相當短。下面是它的完整內(nèi)容:
from __future__ import with_statement from fabric.api import * from fabric.contrib.console import confirm env.hosts = ['my_server'] def test(): with settings(warn_only=True): result = local('./manage.py test my_app', capture=True) if result.failed and not confirm("Tests failed. Continue anyway?"): abort("Aborting at user request.") def commit(): local("git add -p && git commit") def push(): local("git push") def prepare_deploy(): test() commit() push() def deploy(): code_dir = '/srv/django/myproject' with settings(warn_only=True): if run("test -d %s" % code_dir).failed: run("git clone user@vcshost:/path/to/repo/.git %s" % code_dir) with cd(code_dir): run("git pull") run("touch app.wsgi")
但它已經(jīng)涉及到了 Fabric 中的很多功能:
定義 fabfile 任務,并用 fab 執(zhí)行;
用 local 調(diào)用本地 shell 命令;
通過 settings 修改 env 變量;
處理失敗命令、提示用戶、手動取消任務;
以及定義主機列表、使用 run 來執(zhí)行遠程命令。
還有更多這里沒有涉及到的內(nèi)容,你還可以看看所有“參見”中的鏈接,以及 索引頁 的內(nèi)容表。
更多請參考:https://fabric-chs.readthedocs.io/zh_CN/chs/tutorial.html
常用示例
1、上傳文件
fabric可以將本地文件上傳到遠程服務器上,這個操作要用到put函數(shù)
2、示例代碼
#coding=utf-8 from fabric.api import * from fabric.contrib.console import confirm import hashlib host = 'root@192.168.0.62:22' password = '123456' env.hosts=[host] env.password = password def md5sum(filename): fd = open(filename,"r") fcont = fd.read() fd.close() fmd5 = hashlib.md5(fcont) return fmd5 def upload_file(filename): run("mkdir -p /root/upload") with cd('/root/upload'): with settings(warn_only=True): res = put(filename,filename) if res.failed and not confirm("put file failed, Continue[Y/N]?"): abort(u'終止上傳文件') def checkmd5(filename): fmd5 = md5sum(filename) lmd5 = fmd5.hexdigest() target = '/root/upload/'+filename rmd5=run("md5sum " + target).split(' ')[0] if lmd5 == rmd5: print 'ok,the file uploaded' else: print 'error' def uploadfile(filename): upload_file(filename) checkmd5(filename)
執(zhí)行命令 fab -f uploadfile.py uploadfile:filename=fabricdemo1.py
3、程序分析
在執(zhí)行fab命令時,可以指定函數(shù)的參數(shù),多個參數(shù)之間用逗號分隔
with settings(warn_only=True) 的作用,是在發(fā)生錯誤時,不中斷執(zhí)行,只會輸出警告信息
4、上傳文件夾
其實fabric也是可以上傳文件夾的,但是很多教程里都沒有提及,示例代碼如下
def uploadfolder(): run("mkdir -p /root/upload") with cd('/root/upload'): with settings(warn_only=True): res = put('testfolder','.')
在uploadfile.py 同目錄下,有一個testfolder的文件夾,上面的代碼可以將這個文件夾上傳到/root/upload目錄下,主要注意的是put的第二個參數(shù),我這里放的是'.',就表明要把本地的testfolder放到/root/upload目錄下。
不同于上傳文件,文件夾上上傳過程中是不能設置目標文件夾的名字的,目標文件夾必須先存在
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
python?pyvis庫創(chuàng)建可視化交互式網(wǎng)絡圖
這篇文章主要為大家介紹了python?pyvis庫創(chuàng)建可視化交互式網(wǎng)絡圖,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2024-01-01python django下載大的csv文件實現(xiàn)方法分析
這篇文章主要介紹了python django下載大的csv文件實現(xiàn)方法,結(jié)合實例形式分析了Django框架下載csv大文件的相關操作技巧與注意事項,需要的朋友可以參考下2019-07-07python之plt.hist函數(shù)的輸入?yún)?shù)和返回值的用法解釋
這篇文章主要介紹了python之plt.hist函數(shù)的輸入?yún)?shù)和返回值的用法解釋,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-10-10使用Pandas實現(xiàn)高效讀取篩選csv數(shù)據(jù)
在數(shù)據(jù)分析和數(shù)據(jù)科學領域中,Pandas?是?Python?中最常用的庫之一,本文將介紹如何使用?Pandas?來讀取和處理?CSV?格式的數(shù)據(jù)文件,希望對大家有所幫助2024-04-04