基於Jenkins和Kubernetes的CI工作流
摘要
Jenkins作為最為流行的持續整合工具,在結合使用容器技術, Kubernetes 叢集的基礎上, 該如何發揮出新的能力, 在應用微服務化的基礎上, 提供更好的CI方式, 值得我們每一個開發人員去持續不斷的摸索.
本次分享主要介紹我司如何使用Jenkins Pipeline, Container 和 Kubernetes Deployment的能力, 通過增加使用文字模版引擎, 擴充套件Kubernetes Config能力, 完成公司產品開發CI工作流的建立.
Jenkins 和 Kubernetes
Jenkins作為最流行的持續整合工具,有著豐富的使用者群、強大的擴充套件能力、豐富的外掛,是開發人員最為常見的CI工具。在Jenkins 加強其Pipeline功能後,更是可以通過豐富的step庫,實現各種複雜的流程。同時隨著Docker的流行,Jenkins內也增加了對Docker的支援,可以實現容器內流程的執行。
而Kubernetes隨著版本迭代的速度越來越快,在容器圈內的熱度也越來越高,同時每次版本釋出,所新增的功能也不斷增加。做為當前主流的容器管理平臺,其強大的能力無需在此多做介紹。
應用容器化和應用微服務化設計思考
容器化不意味著微服務化,傳統單體應用也可以容器化,但是很難享受到容器化後帶來的好處。微服務化也不是一定要容器化,應用拆解為微服務後,一樣可以不利用容器而是通過傳統的運維來完成系統構建和部署。當微服務化和容器化相結合之後,就能充分利用各方優勢,帶來了彈性伸縮,簡化部署,易於擴充套件,技術相容等優點。
我們在針對應用進行微服務化拆分的過程中,主要先考慮到的是功能點、控制物件、開發組的人員配置安排,產品路線圖規劃等。
例如,針對現有開發組人員人數、分配和各自的技能熟練程度,就可以考慮到服務模組數量的控制,安排好服務模組開發小組;針對功能點和中遠期產品規劃,就可以將特定功能歸納到一個服務模組中,並在版本開發迭代的過程中,通過擴充套件這個服務模組的能力,來完成產品功能的開發,或者暫時將部分功能整合在一個模組中,隨著功能增加或迭代開發,再進行進一步的模組拆分或拆解。
對於模組開發的要求,由於使用了容器技術,對於開發語言或特定框架的選型,可以交給具體的模組開發人員。在團隊內,我們不做強制要求,但是做建議要求,避免出現過多的技術棧,導致後期的維護困難。
在我們團隊內,就只集中在兩種後端開發語言的使用,相應的框架或主要的開發庫,也都有相應而且明確的選擇。對於模組的API介面,使用REST,並且至少按照成熟度模型LEVEL2提供API。
容器環境下的編譯和單元測試
我們整個CI工作流的驅動,都是由Jenkins完成,並且使用了Jenkins Pipeline。第一,Pipeline可以更好的組合job內的stage,重複利用模組間相同的部分,並且隨著開發複雜度的增加來逐步增加擴充套件stage,實現更多所需的功能;
第二,將Pipeline Groovy指令碼來源設定為原始碼內,可以根據原始碼功能點來控制流程,同時也完成了對指令碼的版本管理。
由於有容器這麼個工具,我們各個模組的編譯環境,單元測試環境,也都放到了容器中。各個模組均可以安裝自身模組的執行特性或環境要求,準備自身的編譯環境、單元測試環境、執行環境,因此,程式碼庫內會分別留存相應的Dockerfile,通過不同的Dockerfile完成不同環境映象的準備。
同時,Jenkins現在也可以通過Docker Pipeline外掛,支援在容器內執行step,因此我們利用其功能完成的實際的編譯和測試流程是這樣的:
- 使用編譯環境的Dockerfile構建編譯環境映象。
- 使用編譯環境映象啟動容器並在容器內完成編譯,完成編譯的中間產物也暫存在Workspace中。
- 使用測試環境的Dockerfile構件單元測試環境映象。
- 使用單元測試環境映象啟動容器並在容器內執行單元測試,單元測試指令碼來源於程式碼庫,同時也使用到編譯時生成的中間產物。
- 使用釋出Dockerfile構建實際釋出映象並上傳映象庫。
其中由於編譯環境和單元測試環境不是經常變更,也可以抽出編譯環境映象準備和單元測試環境映象準備兩個步驟放到獨立的CI job中去,需要時手工觸發即可。
服務部署和升級
對於CI流程,在完成編譯和打包後,需要做的就是服務啟動和測試了。我們利用的是Kubernetes Deployment和service,在每次CI流程完成編譯和打包後,通過拿到Build號,作為映象的tag,完成映象的上傳歸檔;同時利用tag,修改Kubernetes中已經建立的Deployment,利用Deployment的Rolling Update,完成升級。
對Kubernetes服務模版和服務配置的擴充套件
我們在實際使用Kubernetes Deployment 升級的方式進行服務部署的過程中,發現其中還是存在很多不方便的地方。
例如:Kubernetes內的同名問題,Kubernetes Deployment升級時的映象tag變更問題,等等各處需要隨著CI流程可能存在變更的地方。
例如在有相同名字的Deployment存在的情況下,後來的Deployment會無法建立,這導致如果想以啟動新的Deployment的方式來測試某個版本,需要修改名稱,對於與Deployment相關的service也一樣,在啟動新的命名後的Deployment,也需要啟動與其對應的service用於暴露服務。
對於Deployment升級所需的映象tag修改,需要每次隨著CI生成了新的映象tag而做變更,因而每次需要修改相應yaml檔案內的映象tag,修改為實際CI流程中生成的值,然後再使用升級功能完成服務升級。
針對這些問題,我們使用了一套文字模板引擎,部署或升級用的yaml檔案本身寫成為模板,可能有變化或者需要根據CI流程變化的位置,使用模板標識佔位,而具體的模板資料內容,則或者通過Jenkins的CI流程獲取,或者使用特定的配置檔案讀取,或者從具體的輸入引數來獲取;
同時,模板資料內容,也會在實際部署時,做為Kubernetes的Configmap設定到系統中,因此資料內容也可以通過Kubernetes使用Configmap的方式來用到環境變數或啟動命令中。通過文字模板引擎,將模板和資料合併後,生成的yaml檔案,再作為後續Kubernetes操作所使用的內容。
通過利用這種方式,我們把需要部署的內容分離成了模板和配置;模板一般在服務架構,使用的映象名,啟動方式或配置引數沒有大的變化的情況下保持不變,而通過不同配置的靈活使用,完成服務升級或拉起新部署,完成不同資料儲存使用的指向,完成對各模組內部配置的修改。
通過利用這種方式,我們的可修改的內容,從Configmap本身只能覆蓋到的環境變數或啟動命令這塊,擴充套件到了啟動名稱,Label,映象等yaml檔案內的各個可填值處,以此來解決同名,映象修改,Label增加或變更等各種使用kubernetes時碰到的問題。
自動化測試
在通過Jenkins拉動完成編譯打包和服務升級部署後,就可以拉動自動化測試了。測試框架我們選擇了使用Robotframework。測試指令碼通過Kubernetes service獲取到服務的具體暴露埠,然後再根據測試指令碼依次執行鍼對API的測試。
測試指令碼的來源,部分是從各模組程式碼庫中,由各模組開發人員提交的針對自身模組的API測試,部分是由測試人員完成撰寫提交的針對跨模組的測試。針對自動化測試這塊,我們的完成度並不是很高,僅僅是搭建起了基本的執行框架,能夠與整個流程對接上。
版本釋出
由於開發的產品本身就是由若干映象構成,因此產品釋出,可以歸結為映象的釋出。在測試通過後,可以簡單的利用映象複製能力,將測試通過的相關映象的版本,通過映象庫間的複製,由開發測試所用的內部映象庫,複製到外部發布映象庫,就可以完成版本釋出,同時可以通過複製時的tag控制,釋出為指定的版本號。
總結
如上介紹,說明了我們在自身開發過程中建立CI流程的做法。對於整個流程的建立,我們並沒有太多需要特殊化處理的地方;對於各項工具的使用,也沒有太多突出之處;我們僅僅根據自身需求,建立了和開發過程適配的CI流。在此介紹我們的CI流程的建立,也是希望拋磚引玉,能從更多處獲得交流和向大家學習的機會。
本文轉自中文社群-ofollow,noindex">基於Jenkins和Kubernetes的CI工作流