基於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,因此我們利用其功能完成的實際的編譯和測試流程是這樣的:

  1. 使用編譯環境的Dockerfile構建編譯環境鏡像。
  2. 使用編譯環境鏡像啓動容器並在容器內完成編譯,完成編譯的中間產物也暫存在Workspace中。
  3. 使用測試環境的Dockerfile構件單元測試環境鏡像。
  4. 使用單元測試環境鏡像啓動容器並在容器內運行單元測試,單元測試腳本來源於代碼庫,同時也使用到編譯時生成的中間產物。
  5. 使用發佈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流程的建立,也是希望拋磚引玉,能從更多處獲得交流和向大家學習的機會。

本文轉自中文社區-基於Jenkins和Kubernetes的CI工作流

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章