Fabric 主要用在應(yīng)用部署與系統(tǒng)管理等任務(wù)的自動(dòng)化,簡(jiǎn)單輕量級(jí),提供有豐富的 SSH 擴(kuò)展接口。在 Fabric 1.x 版本中,它混雜了本地及遠(yuǎn)程兩類功能;但自 Fabric 2.x 版本起,它分離出了獨(dú)立的 Invoke 庫(kù),來(lái)處理本地的自動(dòng)化任務(wù),而 Fabric 則聚焦于遠(yuǎn)程與網(wǎng)絡(luò)層面的任務(wù)。
為了做到這點(diǎn),F(xiàn)abric 主要依賴另一大核心組件 Paramiko,它是基于 SSH 協(xié)議的遠(yuǎn)程控制模塊,F(xiàn)abric 在其基礎(chǔ)上封裝出了更加友好的接口,可以遠(yuǎn)程執(zhí)行 Shell 命令、傳輸文件、批量操作服務(wù)器、身份認(rèn)證、多種配置與設(shè)置代理,等等。
?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-630266.html
一、Fabric 的版本區(qū)分
Fabric 自身存在著 2 個(gè)大版本:Fabric 1 和 Fabric 2,而在這個(gè)庫(kù)的基礎(chǔ)上,還有兩個(gè)很容易混淆的相關(guān)庫(kù):Fabric2 和 Fabric3(注意這里的數(shù)字是庫(kù)名的一部分)。
它們的區(qū)分如下:
Fabric 1.x:支持 Python 2.5-2.7,但不支持 Python 3
Fabric 2.x:支持 Python 2.7 與 3.4+,但不兼容 Fabric 1.x 的 fabfile
Fabric2:等同于 Fabric 2.x,為了使不同版本共存(裝一個(gè) 1.x 舊版本,再裝它作為新版本)
Fabric3:一個(gè)基于 Fabric 1.x 的 fork(非官方),兼容 Python 2&3,兼容 Fabric1.x 的 fabfile
綜上可見(jiàn),我們推薦使用官方的 Fabric 2.x 系列版本,但同時(shí)要注意,某些過(guò)時(shí)的教程可能是基于早期版本的(或非官方的 Fabric3,也是基于 Fabric 1.x),需要注意識(shí)別。
例如,在 Fabric 1.x 系列中這么寫導(dǎo)入:from fabric.api import run;在新版本中將報(bào)錯(cuò):“ImportError: No module named api”(PS:可根據(jù)是否有 fabric.api 來(lái)判斷 Fabric 的版本,就像在 Python 中根據(jù) print 語(yǔ)句或 print 函數(shù)來(lái)判斷版本一樣)。同時(shí),由于新版本不支持老版本的 fabfile,在使用時(shí)就可能報(bào)錯(cuò):“No idea what 'xxx' is!”
Fabric 2 是非兼容性版本,相比于前個(gè)版本,它主要改進(jìn)的點(diǎn)有:
支持 Python 2.7 與 3.4+
線程安全,取消了多進(jìn)程的并發(fā)實(shí)現(xiàn)
API 圍繞 fabric.connection.Connection 進(jìn)行了重組
全面修改了命令行解析器,允許在每個(gè)任務(wù)的基礎(chǔ)上使用規(guī)則的 GNU/POSIX 風(fēng)格的標(biāo)志和選項(xiàng)(不再需要 fab mytask:weird = custom,arg = format)
可以聲明前置任務(wù)與后置任務(wù)
……(官方列了???10幾條?? [1],本文不一一羅列)
之前介紹過(guò)的 invoke,就是在開(kāi)發(fā) Fabric 2 時(shí)被分離出來(lái)的,具體的原因可參見(jiàn)???這個(gè)回答?? [2]??偠灾?,在使用 Fabric 時(shí),應(yīng)該注意版本差異的問(wèn)題。
二、Fabric 的基本用法
安裝PIP
pip是Python包管理工具 可以安裝各類軟件
yum -y install python-pip
升級(jí)PIP
pip install --upgrade pip
檢查PIP版本
pip --versionpip 19.3.1 from /usr/lib/python2.7/site-packages/pip (python 2.7)
安裝docker compose,自行更改版本號(hào).
pip install -U docker-compose==1.24.1
檢查docker compose版本
docker-compose version
?
安裝fabric
1、安裝
首先是安裝:??pip intall fabric?? ,安裝后,可在命令行窗口查看版本信息:
>>> fab -V
Fabric 2.5.0
Paramiko 2.7.1
Invoke 1.4.0
執(zhí)行“fab -V”,以上結(jié)果可看出我安裝的是 Fabric 2.5.0 版本,同時(shí)可看到它的兩個(gè)核心依賴庫(kù) Paramiko 及 Invoke 的版本信息。
2、一個(gè)簡(jiǎn)單的例子
Fabric 主要用于遠(yuǎn)程任務(wù),即要對(duì)遠(yuǎn)程服務(wù)器進(jìn)行操作,下面是一個(gè)簡(jiǎn)單的例子:# 可使用任意的文件名
from fabric import Connection
host_ip = '47.xx.xx.xx' ?# 服務(wù)器地址
user_name = 'root' # 服務(wù)器用戶名
password = '****' ?# 服務(wù)器密碼
cmd = 'date' ?# shell 命令,查詢服務(wù)器上的時(shí)間
con = Connection(host_ip, user_name, connect_kwargs={'password': password})
result = con.run(cmd, hide=True)
print(result)
以上代碼,通過(guò)賬號(hào)+密碼登錄到遠(yuǎn)程服務(wù)器,然后執(zhí)行??date??命令,查看服務(wù)器的時(shí)間,執(zhí)行結(jié)果:
Command exited with status 0.
=== stdout ===
Fri Feb 14 15:33:05 CST 2020
(no stderr)
現(xiàn)在打印的結(jié)果中,除了服務(wù)器時(shí)間,還有一些無(wú)關(guān)的信息。這是因?yàn)樗蛴〉摹皉esult”是一個(gè)"fabric.runners.Result"類,我們可以把其中的信息解析出來(lái):
print(result.stdout) ?# Fri Feb 14 15:33:05 CST 2020
print(result.exited) ?# 0
print(result.ok) ? ? ?# True
print(result.failed) ?# False
print(result.command) # date
print(result.connection.host) # 47.xx.xx.xx
上述代碼使用了 Connection 類及其 run() 方法,可在連接的服務(wù)器上運(yùn)行 shell 命令。如果需要用管理員權(quán)限,則需替換成 sudo() 方法。如果要在本地執(zhí)行 shell 命令,則需替換成 local() 方法。
除此之外,還有 get()、put() 等方法,詳見(jiàn)下文介紹。
3、命令行用法
上例代碼可寫在任意的 .py 腳本中,然后運(yùn)行該腳本,或者稍微封裝下再導(dǎo)入到其它腳本中使用。
另外,F(xiàn)abric 還是個(gè)命令行工具,可以通過(guò)??fab??命令來(lái)執(zhí)行任務(wù)。我們稍微改造一下上例的代碼:# 文件名:fabfile.py
from fabric import Connection
from fabric import task
host_ip = '47.xx.xx.xx' ?# 服務(wù)器地址
user_name = 'root' # 服務(wù)器用戶名
password = '****' ?# 服務(wù)器密碼
cmd = 'date' ?# shell 命令,查詢服務(wù)器上的時(shí)間
@task
def test(c):
? ? """
? ? Get date from remote host.
? ? """
? ? con = Connection(host_ip, user_name, connect_kwargs={'password': password})
? ? result = con.run(cmd, hide=True)
? ? print(result.stdout) ?# 只打印時(shí)間
解釋一下,主要的改動(dòng)點(diǎn)有:
fabfile.py 文件名:入口代碼的腳本名必須用這個(gè)名字
@task 裝飾器:需要從 fabric 中引入這個(gè)裝飾器,它是對(duì) invoke 的 @task 裝飾器的封裝,實(shí)際用法跟 invoke 一樣(注意:它也需要有上下文參數(shù)“c”,但實(shí)際上它并沒(méi)有在代碼塊中使用,而是用了 Connection 類的實(shí)例)
然后,在該腳本同級(jí)目錄的命令行窗口中,可以查看和執(zhí)行相應(yīng)的任務(wù):
>>> fab -l
Available tasks:
? test ? Get date from remote host.
>>> fab test
Fri Feb 14 16:10:24 CST 2020
fab 是 Invoke 的擴(kuò)展實(shí)現(xiàn),繼承了很多原有功能,所以執(zhí)行“fab --help”,與之前介紹的“inv --help”相比,你會(huì)發(fā)現(xiàn)它們的很多參數(shù)與解釋都是一模一樣的。
fab 針對(duì)遠(yuǎn)程服務(wù)的場(chǎng)景,添加了幾個(gè)命令行選項(xiàng)(已標(biāo)藍(lán)),其中:
--prompt-for-login-password:令程序在命令行中輸入 SSH 登錄密碼(上例在代碼中指定了 connect_kwargs.password 參數(shù),若用此選項(xiàng),可要求在執(zhí)行時(shí)再手工輸入密碼)
--prompt-for-passphrase:令程序在命令行中輸入 SSH 私鑰加密文件的路徑
-H 或 --hosts:指定要連接的 host 名
-i 或 --identity:指定 SSH 連接所用的私鑰文件
-S 或 --ssh-config:指定運(yùn)行時(shí)要加載的 SSH 配置文件
關(guān)于 Fabric 的命令行接口,更多內(nèi)容可查看???文檔?? [3]。
4、交互式操作
遠(yuǎn)程服務(wù)器上若有交互式提示,要求輸入密碼或“yes”之類的信息,這就要求 Fabric 能夠監(jiān)聽(tīng)并作出回應(yīng)。
以下是一個(gè)簡(jiǎn)單示例。引入 invoke 的 Responder,初始化內(nèi)容是一個(gè)正則字符串和回應(yīng)信息,最后賦值給 watchers 參數(shù):
from invoke import Responder
from fabric import Connection
c = Connection('host')
sudopass = Responder(
? ? ?pattern=r'\[sudo\] password:',
? ? ?response='mypassword\n')
c.run('sudo whoami', pty=True, watchers=[sudopass])
5、傳輸文件
本地與服務(wù)器間的文件傳輸是常見(jiàn)用法。Fabric 在這方面做了很好的封裝,Connection 類中有以下兩個(gè)方法可用:
get(*args, **kwargs):拉取遠(yuǎn)端文件到本地文件系統(tǒng)或類文件(file-like)對(duì)象
put(*args, **kwargs):推送本地文件或類文件對(duì)象到遠(yuǎn)端文件系統(tǒng)
在已建立連接的情況下,示例:
# (略)
con.get('/opt/123.txt', '123.txt')
con.put('test.txt', '/opt/test.txt')
第一個(gè)參數(shù)指的是要傳輸?shù)脑次募?,第二個(gè)參數(shù)是要傳輸?shù)哪康牡?,可以指定成文件名或者文件夾(為空或 None 時(shí),使用默認(rèn)路徑):
# (略)
con.get('/opt/123.txt', '') ?# 為空時(shí),使用默認(rèn)路徑
con.put('test.txt', '/opt/') # 指定路徑 /opt/
get() 方法的默認(rèn)存儲(chǔ)路徑是??os.getcwd?? ,而 put() 方法的默認(rèn)存儲(chǔ)路徑是 home 目錄。
6、服務(wù)器批量操作
對(duì)于服務(wù)器集群的批量操作,最簡(jiǎn)單的實(shí)現(xiàn)方法是用 for 循環(huán),然后逐一建立 connection 和執(zhí)行操作,類似這樣:
for host in ('web1', 'web2', 'mac1'):
? result = Connection(host).run('uname -s')
但有時(shí)候,這樣的方案會(huì)存在問(wèn)題:
如果存在多組不同的服務(wù)器集群,需要執(zhí)行不同操作,那么需要寫很多 for 循環(huán)
如果想把每組操作的結(jié)果聚合起來(lái)(例如字典形式,key-主機(jī),value-結(jié)果),還得在 for 循環(huán)之外添加額外的操作
for 循環(huán)是順序同步執(zhí)行的,效率太低,而且缺乏異常處理機(jī)制(若中間出現(xiàn)異常,會(huì)導(dǎo)致跳出后續(xù)操作)
對(duì)于這些問(wèn)題,F(xiàn)abric 提出了 Group 的概念,可將一組主機(jī)定義成一個(gè) Group,它的 API 方法跟 Connection 一樣,即一個(gè) Group 可簡(jiǎn)化地視為一個(gè) Connection。
然后,開(kāi)發(fā)者只需要簡(jiǎn)單地操作這個(gè) Group,最后得到一個(gè)結(jié)果集即可,減少了自己在異常處理及執(zhí)行順序上的工作。
Fabric 提供了一個(gè) fabric.group.Group 基類,并由其派生出兩個(gè)子類,區(qū)別是:
SerialGroup(*hosts, **kwargs):按串行方式執(zhí)行操作
ThreadingGroup(*hosts, **kwargs):按并發(fā)方式執(zhí)行操作
Group 的類型決定了主機(jī)集群的操作方式,我們只需要做出選擇即可。然后,它們的執(zhí)行結(jié)果是一個(gè)??fabric.group.GroupResult??類,它是 dict 的子類,存儲(chǔ)了每個(gè)主機(jī) connection 及其執(zhí)行結(jié)果的對(duì)應(yīng)關(guān)系。
>>> from fabric import SerialGroup
>>> results = SerialGroup('web1', 'web2', 'mac1').run('uname -s')
>>> print(results)
<GroupResult: {
? ? <Connection 'web1'>: <CommandResult 'uname -s'>,
? ? <Connection 'web2'>: <CommandResult 'uname -s'>,
? ? <Connection 'mac1'>: <CommandResult 'uname -s'>,
}>
另外,GroupResult 還提供了 failed 與 succeeded 兩個(gè)屬性,可以取出失敗/成功的子集。由此,也可以方便地批量進(jìn)行二次操作。 ???原文??
三、Fabric 的進(jìn)階用法
1、身份認(rèn)證
Fabric 使用 SSH 協(xié)議來(lái)建立遠(yuǎn)程會(huì)話,它是一種相對(duì)安全的基于應(yīng)用層的加密傳輸協(xié)議。
基本來(lái)說(shuō),它有兩種級(jí)別的安全認(rèn)證方式:
基于口令的身份認(rèn)證:使用賬號(hào)與密碼來(lái)登錄遠(yuǎn)程主機(jī),安全性較低,容易受到“中間人”攻擊
基于密鑰的身份認(rèn)證:使用密鑰對(duì)方式(公鑰放服務(wù)端,私鑰放客戶端),不會(huì)受到“中間人”攻擊,但登錄耗時(shí)較長(zhǎng)
前文在舉例時(shí),我們用了第一種方式,即通過(guò)指定 connect_kwargs.password 參數(shù),使用口令來(lái)登錄。
Fabric 當(dāng)然也支持采用第二種方式,有三種方法來(lái)指定私鑰文件的路徑,優(yōu)先級(jí)如下:
優(yōu)先查找 connect_kwargs.key_filename 參數(shù),找到則用作私鑰
其次查找命令行用法的 --identify 選項(xiàng)
最后默認(rèn)使用操作系統(tǒng)的 ssh_config 文件中的??IdentityFile?? 的值
如果私鑰文件本身還被加密過(guò),則需要使用 connect_kwargs.passphrase 參數(shù)。
2、配置文件
Fabric 支持把一些參數(shù)項(xiàng)與業(yè)務(wù)代碼分離,即通過(guò)配置文件來(lái)管理它們,例如前面提到的密碼和私鑰文件,可寫在配置文件中,避免與代碼耦合。
Fabric 基本沿用了 Invoke 的配置文件體系(官方文檔中列出了 9 層),同時(shí)增加了一些跟 SSH 相關(guān)的配置項(xiàng)。支持的文件格式有 .yaml、.yml、.json 與 .py(按此次序排優(yōu)先級(jí)),推薦使用 yaml 格式(后綴可簡(jiǎn)寫成 yml)。
其中,比較常用的配置文件有:
系統(tǒng)級(jí)的配置文件:/etc/fabric.yml
用戶級(jí)的配置文件:~/.fabric.yml(Windows 在 C:\Users\xxx 下)
項(xiàng)目級(jí)的配置文件:/myproject/fabric.yml
以上文件的優(yōu)先級(jí)遞減,由于我本機(jī)是 Windows,為了方便,我在用戶目錄建一個(gè)".fabric.yml"文件,內(nèi)容如下:
# filename:.fabric.yml
user: root
connect_kwargs:
? password: xxxx
# 若用密鑰,則如下
# ?key_filename:
# ? ?- your_key_file
我們把用戶名和密碼抽離出來(lái)了,所以 fabfile 中就可以刪掉這些內(nèi)容:
# 文件名:fabfile.py
from fabric import Connection
from fabric import task
host_ip = '47.xx.xx.xx' ?# 服務(wù)器地址
cmd = 'date' ?# shell 命令,查詢服務(wù)器上的時(shí)間
@task
def test(c):
? ? """
? ? Get date from remote host.
? ? """
? ? con = Connection(host_ip)
? ? result = con.run(cmd, hide=True)
? ? print(result.stdout)
然后,在命令行中執(zhí)行:
>>> fab test
Tue Feb 18 10:33:38 CST 2020
配置文件中還可以設(shè)置很多參數(shù),詳細(xì)可查看???文檔?? [4]。
3、網(wǎng)絡(luò)網(wǎng)關(guān)
如果遠(yuǎn)程服務(wù)是網(wǎng)絡(luò)隔離的,無(wú)法直接被訪問(wèn)到(處在不同局域網(wǎng)),這時(shí)候需要有網(wǎng)關(guān)/代理/隧道,這個(gè)中間層的機(jī)器通常被稱為跳板機(jī)或堡壘機(jī)。
Fabric 中有兩種網(wǎng)關(guān)解決方案,對(duì)應(yīng)到 OpenSSH 客戶端的兩種選項(xiàng):
ProxyJump:簡(jiǎn)單,開(kāi)銷少,可嵌套
ProxyCommand:開(kāi)銷大,不可嵌套,更靈活
在創(chuàng)建 Fabric 的 Connection 對(duì)象時(shí),可通過(guò)指定 gateway 參數(shù)來(lái)應(yīng)用這兩種方案:
ProxyJump 方式就是在一個(gè) Connection 中嵌套一個(gè) Connection 作為前者的網(wǎng)關(guān),后者使用 SSH 協(xié)議的??direct-tcpip?? 為前者打開(kāi)與實(shí)際遠(yuǎn)程主機(jī)的連接,而且后者還可以繼續(xù)嵌套使用自己的網(wǎng)關(guān)。
from fabric import Connection
c = Connection('internalhost', gateway=Connection('gatewayhost'))
ProxyCommand 方式是客戶端在本地用 ssh 命令(類似“ssh -W %h:%p gatewayhost”),創(chuàng)建一個(gè)子進(jìn)程,該子進(jìn)程與服務(wù)端進(jìn)行通信,同時(shí)它能讀取標(biāo)準(zhǔn)輸入和輸出。
其他參考文檔
pip install Fabric # 安裝
pip freeze > requirements.txt # 把安裝包寫入文件中
一個(gè)官網(wǎng)例子:
def hello(name='sitin'): print("Hello world %s!" % name)
使用fab執(zhí)行一下效果如下:
這里面我們需要知道fab是fabric安裝的命令行工具,我們主要是通過(guò)它進(jìn)行操作。
我個(gè)人平時(shí)用的比較多的命令有:
run 遠(yuǎn)端執(zhí)行命令
local 本地執(zhí)行命令
cd 遠(yuǎn)端切換目錄
lcd 本地切換
@task 裝飾器聲明函數(shù)為fab task
簡(jiǎn)單的腳本我覺(jué)得是已經(jīng)夠用了,復(fù)雜一點(diǎn)需要更多操作了,詳情見(jiàn)后文。
部署步驟
通常情況下,作為一個(gè)Python工程師我們發(fā)布代碼需要做的事兒常見(jiàn)的有以下幾點(diǎn):
- git pull 拉取最新代碼,比如master分支(或者develop分支)
- tar 打包最新代碼
- rsync增量同步到遠(yuǎn)端服務(wù)器,去掉一些不需要的本地目錄
- 備份數(shù)據(jù)庫(kù)或者備份代碼
- supervisor指定重啟遠(yuǎn)端一個(gè)或多個(gè)服務(wù),通過(guò)交互式指令判斷
- sentry查看日志正常與否
除了最后一步,這里面所有的操作我們都在fabfile.py就進(jìn)行操作了,一般情況下fabfile.py放在項(xiàng)目根目錄,當(dāng)然你放在其他地方也沒(méi)有什么問(wèn)題。通過(guò)-f進(jìn)行指定就行。
概要講了,下面請(qǐng)參看我們的一個(gè)實(shí)戰(zhàn)例子
一個(gè)例子
from fabric.api import ( with_settings, hosts, cd, # 遠(yuǎn)端 lcd, # 本地切換目錄 run, # 執(zhí)行 env, ) EST_ENV = '127.0.0.1' TEST_USER = 'test' env.forward_agent = True# 允許本地 SSH 代理連接遠(yuǎn)程終端時(shí)跳轉(zhuǎn) @hosts(TEST_ENV) # 指定遠(yuǎn)程操作的機(jī)器地址 @with_settings(user=TEST_USER) # 用來(lái)臨時(shí)設(shè)定 env 變量,可以等同于 with settings def deploy_test(): # 發(fā)布測(cè)試環(huán)境 local('git pull --rebase upsgream dev') # local執(zhí)行本地命令拉取代碼到本地,這個(gè)可以用CI自動(dòng)發(fā)布,就不用拉取到本地。 local('rsync -r . --exclude=tmp/ --exclude=backup/ sitin@yourip:/data/your_project') # 上傳代碼 with cd('/data/your_project'): # 表示所有操作在這個(gè)目錄下面 run('docker-compose pull test') # test鏡像名 backup_db() # 這里其實(shí)就是一個(gè)普通備份函數(shù) run('docker-compose stop test') # 執(zhí)行遠(yuǎn)端命令同local相反 run('docker-compose rm -f test') run('docker-compose run --rm test python manage.py migrate') # db同步 run('docker-compose up -d test')
在終端執(zhí)行命令
fab deploy_test # 就能進(jìn)行發(fā)布了測(cè)試環(huán)境了
fab deploy_product # 如果有就能發(fā)布了
通常情況下測(cè)試,開(kāi)發(fā),服務(wù)器與線上操作不太一樣,我們可以通過(guò)上面方式進(jìn)行操作。除了上面的操作之后,如果我們測(cè)試線上完全一直或者多臺(tái)服務(wù)器,可以通過(guò)指定不同角色來(lái)進(jìn)行選擇服務(wù)器的發(fā)布。
env.roledefs = { 'test': ['test@yourip'], # 指定多臺(tái)機(jī)器 'dev': ['dev@yourip'], 'prod': ['opt@yourip2'], } def deploy(branch=master): pass
fab -R test(上面定義的角色) deploy -f fabfile.py
deploy這里還可以指定發(fā)布哪個(gè)分支的代碼
這樣指定某一個(gè)角色的服務(wù)器,某一個(gè)分支進(jìn)行發(fā)布非常簡(jiǎn)單方便,對(duì)于經(jīng)常使用的復(fù)雜命令操作我們還可以作為縮寫命令來(lái)進(jìn)行操作。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-630266.html
?
到了這里,關(guān)于K8S系列文章之 自動(dòng)化運(yùn)維利器 Fabric的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!