部署流水線的通用法則
前言
近些年來Docker、 Kubernetes、 Helm、 云原生如火如荼,Jenkins 憑借開源社區的貢獻以及類似 CloudBees 團隊的加持。緊跟技術發展趨勢,產出了集成于 Docker、 Kubernetes、 Helm、AWS等各種工具插件,還有 Jenkins X,原來配置頁的 Manage Nodes 也"悄悄地"變成了 Manage Nodes and Clouds。 另一方面,自研能力不錯的企業,也紛紛基于 Jenkins API開發一套 Devops CICD 平臺,給 Jenkins那個"老頭"套上了一層年輕的外衣,效果也十分理想。
Jenkins開源的特性,還有浩瀚如海的插件,學習門檻低等等,都讓其成為一個不錯的選擇。至少可以在有限資源的條件下,針對項目中需要搭建少數的幾個流水線這樣的需求而言,Jenkins再合適不過了。
縱使作為一個新技術的愛好者,當你用戶其他新的CI工具時,也不妨回過頭來看一看這個“老頭”,其中包含的一些通用法則、思想會讓你明白如何才能搭建使用于某個項目易用、易擴展、易維護的流水線。
提高代碼復用性之Shared Library
如果你為一個項目里的多個Code Repo寫多個jenkinsfile,你八成會遇到多個不同流水線中有大量重復代碼的情況,尤其在服務眾多的微服務的項目當中。很多時候為了方便省事我們都是直接復制粘貼類似的邏輯代碼到不同的jenkinsfile中去,但如果某一天你需要更改一個小小的命令,那你就要受點小罪了。
而Shared Library便是解決代碼重復的方法之一,只需根據流水線段落的合理劃分,將流水線邏輯重復或共通的部分進行抽象和封裝,便可在所有的流水線中簡單地引用這些共享庫下面的代碼,并可大大縮短jenkinsfile中的代碼行數,也顯得更加易讀、易維護。
而后期之秀中的Azure Pipelines, Github Actions 似乎深知復用功能函數的好處,并將其常用的Tasks/Actions放置到了公共的Marketplace中。開發者即可直接使用,也可以自行開發后上傳到Marketplace中供更多人使用。使用者更是免于維護一個單獨的類似于Jenkins Shared Libray的代碼倉庫,一舉多得。另外,云原生工具中的Tekton, 其中的Task也有類似的實踐。
共享庫越來越大,調用關系越來越復雜時,不得不考慮代碼質量的問題。那就需要測試代碼來保證質量,如何對Shared Library進行測試?當然可以編寫Jenkinsfile放到Jenkins中創建Job去運行,跑一跑便知代碼是否有問題。但無疑這種方法不太優雅,推薦使用JenkinsPipelineUnit(一個共享庫單元測試的框架)。
模板化之 JTE
正如一套開發框架一樣,目的是為了快速地搭建起一個標準化的許多項目,模板提供的功能也是如此:對于同一類型的流水線而言,大多數的構建過程均是一樣的,甚至連運行的命令也是一模一樣,這樣的流水線 配置文件相似度自然也是非常的高。那么 Jenkins Templating Engine就是針對這樣的場景的一個非常好的解決方案。
例如,在微服務的大型項目中,往往一個系統是由數十個小的微服務組成的,而著數十個微服務均需要各自的CICD的流水線,來完成打包、部署的過程,彼此之間又是同一套開發框架,所需要的構建環境、工具、測試流程、發布策略等等均是一個模子刻出來的。
"人"如其名, Jenkins Templating Engine就是用來做流水線模板化的工具,簡稱 JTE。從 JTE 主頁可看到誕生時間是2019年5月份,相當年輕。針對不同類型的項目,比如Maven、 Gradle來做一些模板化的規定,簡單而言就是用來統一內部流水線的Stage、Steps中的邏輯、參數等。
在完成上述代碼,以及安裝JTE插件、正確配置 Jenkins的前提下,在具體業務代碼中添加默認文件pipeline_config.groovy之后,新建流水線時針對 build configuration 選項去選擇Jenkins Templating Engine,即可完成流水線的搭建,只需要簡簡單單的2、3行。
而反觀 JTE 的優勢,便是以下三點:
(來源于 https://www.jenkins.io/blog/2019/05/09/templating-engine/)
而去其他CICD工具中尋找一下,也可見到類似實踐的身影。例如 Gocd 的Pipeline Templates, Azure Pipelines 的 templates。
集中管理之Job DSL
如果你正在經歷一個微服務項目,Code Repo 數量眾多,而每個Repo都需要通過一個Jenkinsfile定義一個流水線。當你面對幾十上百個Repo,分散地管理維護它們便些許繁瑣。Job DSL Plugin 允許使用DSL以編程方式創建項目,將作業創建的操作通過腳本實現,使你能夠自動化和標準化 Jenkins 配置。
這款插件不單單能夠創建各種類型的Job(Maven jobs、Freestyle jobs、流水線 jobs...),還能創建 Folder、 Dashboard View、 List View等等。形象生動的效果如下圖,“埋下一顆種子,收獲幾顆大樹”。
在代碼庫的目錄層級上,首先建議按照 Project 劃分,給每個 Project 定義單獨的 Seed Job;其次將Job等的定義與邏輯實現隔離,這樣能確保 xxx.jenkinsfile 里的內容的獨立性,且在采納Job DSL插件后,針對原先的 jenkinsfile 無需做很大幅度的修改,拿過來便可使用。
該工具無疑將Pipeline As Code的理念又進化了一步,將流水線的創建過程也代碼化了。然后在 Jenkins 實踐中,如果想追求更多的配置代碼化,不妨看看 Jenkins Configuration as Code,簡稱 JCasC。這個工具能完全將大部分的Jenkins的資源、配置代碼化,安裝插件、配置Github Server、管理憑證、新建任務等等都可通過文件完成,不需要在UI界面上做任何的操作。
后記
以上幾種思想在本文中都提供了對應的一種實現方式,但遠遠不止于所提及的方法,當然還有或多或少類似的方法,但萬變不離其宗。縱使今后有更多的CICD新工具的出現,或許在一些小的地方上可以另辟蹊徑,但大體的解決方案也繞不開已有的這些解決問題的思想。例如在Azure Pipelines中, Templates的功能能提供類似 Shared Library 和 JTE的功能,只是實現形式不同,核心思想卻還是一致的。
具體使用還需要結合項目屬性、分支策略、發布策略、權限管理、服務器環境情況等多個方面綜合考慮,另外也有很多類似于 Nightly Build 這種構建策略值得我們借鑒。“條條道路通羅馬”,怎么省時、省力的達成我們最終的目標,以及達成之后如何維護好流水線,都值得好好思考與設計。