在Python Web專案中使用Jenkins進行持續整合
在一個專案的開發過程中,往往會有一些需要反覆執行的操作,比如編譯、測試、部署。具體於Flask專案,我一般使用nose執行單元測試、fabric進行部署、pylint執行程式碼質量檢測等。這些頻繁需要執行的步驟,是非常枯燥的,那何不交給機器來自動執行呢?最近,我參與的一個校內團隊也遇到了類似的問題,於是打算調研一下相關的工具。
還是習慣性地查閱了下Kenneth Reitz大神的python-guide,果然找到了關於CI的章節。選來選去,最終沒有選擇Python
Stack的Buildbot,而是更加成熟的Jenkins。Jenkins基於Java開發,是業界使用得最多的一款持續整合系統,市場份額佔到了
關於Jenkins,官方的介紹如下:
monitors executions of repeated jobs, such as building a software project or jobs run by cron。
文件中也說目前Jenkins專注於以下2個點:
- Building/testing software projects continuously
- Monitoring executions of externally-run jobs
其實Jenkins能夠做的遠不止這兩點,你可以把它理解成可以自動執行任務(類似cron)並收集報告的基礎工具。再加上它有著非常豐富的外掛庫,所以使用起來應該是很靈活的。
下面記錄一些在Python Web專案中應用Jenkins的經驗。
安裝
需要提的一點是Jenkins比較耗記憶體,不執行任何構建任務的情況下就吃掉了300多M,再加上構建任務時會佔用更多,所以建議伺服器的記憶體至少有1G,512M的話很可能在執行構建任務的時候記憶體不夠用。
訪問控制
外掛清單
下面是我用到的一些外掛:
- Git Plugin:使用Git作為原始碼管理
- SSH plugin:遠端ssh登入server執行命令
- Parameterized Trigger Plugin:觸發其他的job
- Cobertura Plugin:程式碼測試覆蓋率報告
- Task Scanner Plugin:檢測程式碼中出現的特殊標記(如TODO等)
- Violations:程式碼質量檢測,支援pylint、jslint等
- ThinBackup:用於備份Jenkins
- SCM Sync configuration plugin:將Jenkens的配置變更同步到SCM中
這裡只是集中地列舉一下,具體的使用會在下面穿插介紹。
測試、Staging部署、Production部署流程
根據本專案的需要,在Jenkins中建立了3個任務:
- tm_test:用於執行測試、程式碼質量檢測等
- tm_staging_deploy:用於在staging伺服器上deploy程式碼
- tm_deploy:用於在production伺服器上deploy程式碼
其中staging伺服器用於進行線上測試,staging伺服器和production伺服器的環境必須保持完全相同(當然,staging伺服器配置可以低一些)。
具體的開發、測試、部署流程是:
- 在開發新功能/修復bug的時候,一般是開新分支;但如果是那種很小的修改,則直接在master上改,這樣比較省事兒
- 新功能開發完成/bug修復後,進行單元測試+人工測試,如果通過,合併到master
- 每次master有變動後,觸發tm_test任務,執行整合的單元測試和程式碼質量檢測,如果OK,則自動觸發tm_staging_deploy,部署到staging伺服器上
- 若tm_staging_deploy成功,則登陸到執行在staging伺服器的測試網站上,人工測試新功能是否OK/bug是否已修復;若tm_staging_deploy失敗,檢查失敗原因,進行修復,直至成功
- 若staging人工測試通過,則手動觸發tm_deploy,部署到生產伺服器上
- 登入到生產伺服器上進行人工測試,若出現問題,進行修復;同時密切關注Sentry傳送的告警郵件,爭取在第一時間修復錯誤
比較簡單,沒有采用Git-Flow/GitHub-Flow,單元測試寫得很淺,也沒有做程式碼審查。不過團隊規模小,從目前來看,上面的流程是夠用的。
下面對這三個任務做較為詳細的介紹。
tm_test
該任務用於執行測試、程式碼質量檢測等。
push觸發構建
每當專案倉庫的master分支有變動時,即會觸發tm_test。要做這一點,需要如下步驟:
- 設定tm_test的Build Triggers為Poll SCM,但不填Schedule
- 為專案倉庫新增Web Hook,URL填寫
http://<Jenkins URL>/git/notifyCommit?url=<URL of the Git repository>
使用virtualenv配置測試環境
執行測試之前,需要確定Python版本(一般是2.7),然後根據此版本初始化virtualenv。
在構建中新增Execute shell項:
if [ ! -d "venv" ]; then virtualenv -p /usr/bin/python2.7 venv fi . venv/bin/activate pip install -i http://pypi.douban.com/simple -r requirements.txt
測試與報告
測試中需要2個庫:nose用於執行單元測試,coverage用於統計測試覆蓋率。
需要在Jenkins中安裝Cobertura Plugin外掛,用於生成程式碼測試覆蓋率報告。
然後在構建中新增Execute shell項,輸入:
nosetests --with-xunit --with-coverage --cover-package=tm && coverage xml
其中--with-xunit
告訴nose輸出JUnit形式的測試報告,--with-coverage
表示同時執行coverage(這個功能相當贊),--cover-package=tm
表示僅對指定的package執行測試覆蓋率檢測,後面的coverage
xml
表示輸出xml格式的coverage報告。
然後在構建後操作中,新增如下2項:
- Publish JUnit test result report:填寫nosetests.xml
- Publish Cobertura Coverage Report:填寫coverage.xml
這樣一來,就可以執行測試,並得到測試報告和測試覆蓋率報告啦:
上面的圖表都是可點選的,點進去後有程式碼級的詳細報告,非常贊:
綠色的程式碼行表示已經覆蓋到,紅色則沒有。
程式碼質量檢測
Jenkins有一個蠻不錯的程式碼質量報告外掛:Violations,支援非常多的程式碼測試工具。目前專案中使用Pylint做Python程式碼質量檢測,使用JSHint做JavaScript程式碼質量檢測。
在安裝好Pylint後,執行pylint --generate-rcfile > pylintrc
生成配置檔案,並將其中的output-format
項的值改為parseable
。
然後在構建中新增2項Execute shell項,
pylint:
pylint tm2 > pylint.xml || exit 0
jshint:
jshint --reporter=jslint $WORKSPACE/tm2/static/js/ > jslint.xml || exit 0
其中的exit 0
是為了告訴Jenkins該命令執行成功。對於jshint來說,report選擇jslint,然後需要使用$WORKSPACE
組成絕對路徑,否則無法看到原始碼級的分析報告(是不是一個bug?)。
然後在構建後步驟中新增Violations Report,在對應位置輸入jslint.xml和pylint.xml。
最終的圖形報告如下,可以看到趨勢走向:
原始碼級別的分析也有:
檢測程式碼中的特殊標註(如TODO)
團隊中約定,在程式碼未完成的地方使用TODO
進行標記,因為PyCharm有一個很好的功能就是可以檢測出程式碼中的所有TODO資訊:
Jenkins中也有一個非常棒的外掛Task Scanner Plugin用於檢測程式碼中出現的特殊標記,當然,這些特殊標記完全是可以自定義的。
安裝完該外掛後,在構建後操作中新增一項Scan workspace for open tasks,根據需要填寫配置:
然後報告就可以出來啦:
郵件告警
如果構建後狀態是unstable或failed,則可以傳送郵件告警,及時通知相關負責人進行處理。Jenkins自帶SMTP功能,不過需要你提供SMTP伺服器。
我使用的是qq郵箱SMTP伺服器,挺好用的,目前沒有發現拒發的情況。有一點需要注意的是,在配置好SMTP的賬戶資訊後,還需填寫系統管理員郵件地址,否則會發送失敗,這也是比較容易忽略的地方。
配置好SMTP後,然後在構建後操作中新增E-mail Notification項,填寫負責人的郵箱即可。
觸發下游任務
如果tm_test構建成功,則需要自動觸發tm_staging_deploy任務,這個觸發過程是通過外掛Parameterized Trigger Plugin來完成的。
在構建後操作中新增Trigger parameterized build on other projects項,選擇觸發條件為stable,然後填寫待出發的任務名稱即可。
最後的tm_test任務面板如下:
介面是挺out的,不過很實用。
tm_staging_deploy
這一個job用於將最新程式碼部署到staging伺服器上,我採用的部署方法是通過ssh遠端登陸伺服器執行命令的方式,需要一個外掛SSH plugin。
然後在構建中新增Shell項:
cd /var/www/tm export MODE=PRODUCTION git reset --hard HEAD git pull -f source venv/bin/activate pip install -r requirements.txt python manage.py db upgrade supervisorctl restart tm
tm_deploy
此任務和tm_staging_deploy基本差不多,不同的地方有2個:(1)目標伺服器不同(2)觸發方式是手動觸發
備份
使用thinBackup進行備份,可設定備份週期。
配置變更同步
除此之外,我還用到了一個很有用的外掛SCM Sync configuration plugin,就是把Jenkins的配置(全域性配置+各job配置)同步到一個Git倉庫中。這樣的話,每次配置有變動,都會形成一個commit推送到Git倉庫。
這相當於把配置的歷史變遷都記錄下來,如果哪天Jenkins任務掛了,可以看看配置變更進行排錯。
就這些,如果你好的建議,歡迎反饋!
參考
· EOF ·