在持續整合/灰度發布越來越流行的今天,模組在預覽或生產環境的部署流程自動化顯得越來越重要。本文要介紹的fabric就是乙個幫助我們在上線時減少重複/繁瑣操作的自動化部署利器,對於缺乏成熟運維平台的眾多小公司的運維或開發人員來說,掌握這個工具是有必要的。
在系統運維和部署自動化領域,與fabric類似的工具還有很多(如puppet, chef),感興趣的話,可以參考這篇文章48 best cloud tools for infrastructure automation的介紹。
fabric的安裝非常方便,pip install fabric就可以搞定,這裡不贅述。
fabric支援的常用命令行出如下:
1)local
run a command on the local system.
它是對subprocess模組的封裝(shell=true),可以通過設定capture = true/false來捕獲其執行結果。
2)run
run a shell command on a remote host.
該命令的返回值包含了遠端命令是否執行成功以及遠端命令的返回碼等資訊。通過run執行命令時,通常會要求輸入目標機器密碼,如果對多台機器進行部署,可以通過設定env.passwords來避免手動輸入密碼,具體的設定方法會在下篇筆記中介紹。
3)get
download one or more files from a remote host.
4)put
upload one or more files to a remote host.
5)sudo
run a shell command on a remote host, with superuser privileges.
功能與run操作類似,它可以對當前使用者臨時提權來執行某些需要root許可權的命令。
此外,還有些不常用的命令(如:prompt, reboot, open_shell, require)這裡沒有列出,感興趣的話,可以參考fabric operations文件。
需要特別注意的是,fabric通過run或sudo執行遠端任務時,每次都會新建ssh連線,也即任務之間是不會耦合狀態的,所以在實現需要多步操作的任務時,需要把多個命令放入同一行,命令間用逗號隔開。例項說明如下:
假設要在遠端機器上cd至/home/work/tmp目錄後建立test目錄,則下面的命令無法實現預期目的:
需要用下面的命令來實現:run('cd /home/work/tmp')
run('mkdir test') ## 第2次run會重新建立ssh連線,且不會記憶上次cd到的目錄!
!
run('cd /home/work/tmp; mkdir test')
或
run('cd /home/work/tmp && mkdir test')
當然,還可以借助fabric提供的context manager來實現:
關於fabric支援的context managers,還有很多強大且好玩的功能,請參考官方文件fabric context managers,不會讓你失望的。with cd('/home/work/tmp'):
run('mkdir test')
上面介紹了fabric支援的元操作,那麼如何基於這些操作實現複雜功能呢?
在fabric中,一組具有邏輯關係的操作通常被封裝成乙個task,fabric以task為粒度來執行命令,下面開始介紹如何定義task。
3.1 fabfile是什麼
根據fabric的約定,當執行例如」fab deploy」這樣的命令時,fab會預設搜尋名為fabfile.py的python檔案或名為fabfile的package,故基於fabric的部署指令碼通常以fabfile.py命名且應該位於當期工作目錄下以便於fab進行搜尋,在該檔案中實現我們想要的任務即可。當然,如果要實現的部署任務比較複雜,這些任務也可以寫在多個指令碼中,統一置於fabric package下。關於fabfile的細節,可以參考官方文件fabfile construction and use,這裡不贅述。
3.2 定義task
在語法約定上,fabric有兩種定義task的方式:
1)經典方式(classic method)
所有定義在fabfile中的可呼叫物件(如函式、類)均可被當作task被fab執行,這種方式不支援巢狀,也即:若fabfile.py中import了其它模組,則即使這些模組中定義了可呼叫物件,這些不是直接定義在fabfile中的可呼叫物件也不會被當作fab task。
以classic方式定義的task示例下(摘自fabric overview and tutorial):
上述示例**在fabfile.py中定義了乙個普通函式prepare_deploy,不難看出,其功能是在本地執行**測試後,將本地的最新codebase更新到版本管理系統中以便後續以該codebase進行部署。from fabric.api import local
defprepare_deploy
(): local("git add -p && git commit")
local("git push")
2)基於task類的新風格task
從fabric 1.1開始,這種new-style的task定義方式被引入。該方式約定,所有的fab任務必須定義成task類的例項或子類,其最大的優點是支援巢狀namespaces,也即,task可以定義在其它檔案,fabfile.py通過import引入該檔案後,定義在該檔案的task也是可以被fab識別並支援的。
在new-style方式定義task的具體實現上,由2種方法:a. 定義乙個繼承自task的子類並為其實現run()方法; b. 借助@task裝飾器。示例分別如下:
上述示例與借助@task定義task的方式等價:class
mytask
(task):
name = "deploy"
## 指定task name,會在fab --list輸出中顯示
defrun
(self, environment, domain="whatever.com"):
run("git clone foo")
sudo("service apache2 restart")
instance = mytask()
被@task裝飾的函式預設繼承自task類,我們可以讓函式繼承自定義的類,具體的用法可以參考文件defining tasks的」using custom subclasses with @task」部分,這裡只是拋磚引玉,不再贅述。@task
defdeploy
(environment, domain="whatever.com"):
run("git clone foo")
sudo("service apache2 restart")
需要特別注意的是,這兩種task的定義方式是互斥的!具體而言,如果fabric在fabfile或它import的檔案中發現了基於task類的new-style定義,那麼,所有以classic方式定義的task(s)均會被fabric忽略。個人認為,如果要用fabric實現複雜系統的自動化部署,最好以new-style定義任務,因為這種方式支援巢狀namespace,可以用不同的指令碼檔案分層組織不同的任務,更方便維護。
備註:可以執行」fab –list」來檢視fabric可以識別的任務。
完成task定義後,fabric是如何執行的?尤其是遠端部署多台機器時,如何更好地管理這些機器(如角色、密碼等)?
這些問題會在下篇筆記中進行說明。
參考資料
[1] 48 best cloud tools for infrastructure automation
[2] deployment management tools: chef vs. puppet vs. ansible vs. saltstack vs. fabric
[3] fabric doc: overview and tutorial
[4] fabric doc: operations
[5] fabric doc: context managers
[6] fabric doc: defining tasks
fabric 自動化部署
專案發布和運維的工作相當機械,頻率還蠻高,導致時間浪費在敲大量重複的命令上。修復bug什麼的,測試,提交版本庫 2分鐘 ssh到測試環境pull部署 2分鐘 rsync到線上機器a,b,c,d,e 1分鐘 分別ssh到abcde五颱機器,逐一重啟 8 10分鐘 13 15分鐘 其中鬱悶的是,每次操作...
有關自動化部署Fabric
要部署多台生產伺服器的時候,一台一台去配置不方便,所以我們需要自動化部署的方式來部署。本文採用的是fabric,在ubuntu 64 上實現。fabric python內建的模組,用來提高基於 ssh 的應用部署和系統管理效率。可以實現與遠端伺服器的自動化互動。一般使用情況為需要運維幾台至幾百台機器...
使用 Fabric 自動化部署
fabric 目前僅支援 python2,如果你的系統中只有 python3 版本,可以使用 fabric3,但是只能安裝低版本1.14.post1,高版本不支援api方法。接下就可以簡單地通過 pip 命令安裝 fabric 了。如果是 python 2 pip install fabric 如果...