1. 前言
隨著網際網路軟體行業快速發展,為了搶佔市場先機,企業不得不持續提高軟體的交付效率。特別是現在國內越來越多企業已經在逐步引入DevOps研發模式的變遷,在這些背景催促之下,對於企業研發團隊所需要具備的持續整合和持續交付(簡稱CI/CD)能力變得越來越不可或缺。
相信現在不管是開發人員、測試人員或者是運維人員,在求職招聘時,基本上如果是面試的是中高階以上的職位,大多都要求要具備相關CI/CD的專案建設或參與搭建經驗。
為了幫助到更多技術讀者,從本週起,將以《持續整合實踐系列》為主題,分享幾篇搭建CI持續整合實踐的技術乾貨。
關於持續整合和持續交付(CI/CD)概念的介紹,之前的文章:《DevOps研發模式下CI/CD實踐詳解指南》 中有過較詳細的介紹,如果還不清楚什麼是CI/CD的讀者,可以在閱讀本文前先,參考一下這篇文章。
2. CI系列大綱
市面上關於CI/CD的建設如果僅從工具、框架層面來講,方案有挺多,如TeamCity
、GitLab CI
、Bamboo
、Circle CI
、Travis CI
、Jenkins
、公司自研
(在研發建設CI/CD能力時,除了CI/CD工具、框架鏈的建設外,還包括研發協同文化的建設等, 文化層面的這個不在本系列的討論範圍內)。
而在眾多的持續整合CI建設工具體系中,Jenkins基本上可以說是獨佔鰲頭,也是大多數公司最常用、最首選的工具之一,佔據了將近70%以上的市場。
而隨著Jenkins本身的不斷髮展,當前Jenkins已演變發展到了2.x系列,在Jenkins 2.x系列中,其中最核心的特性是引入了流水線機制,並提出了流水線即程式碼(pipeline as code)的理念。
因此本系列也將以Jenkins 2.x作為《持續整合實踐系列》的載體,為大家介紹在結合Jenkins 2.x搭建持續整合CI能力過程中常見的一些知識要點和實現過程。
系列大綱分為(初步擬訂):
- Jenkins 2.x 搭建CI需要掌握的硬核要點(一)
- Jenkins 2.x 搭建CI流水線執行流程(二)
- Jenkins 2.x 搭建CI流水線實現案例(三)
- Jenkins 2.x 搭建CI流水線通知機制(四)
- Jenkins 2.x 搭建CI擴充套件流水線:自定義共享庫(五)
PS: 當然Jenkins 2.x & CI流水線的知識要點遠不止如此。
3. 先介紹一下Jenkins 2.x
Jenkins 2本身的概念比較寬泛。在特定的上下文環境中,它用來泛指支援流水線即程式碼及其它類似Jenkinsfile等新特性的新版Jenkins。
Jenkins 1.X版本主要通過外掛的方式來實現,確切地講,Jenkins 2也是通過對已有外掛的重點升級和新外掛的引入來獲取新功能。
相比之前,使用者只能通過WEB介面進行配置的方式來定義Jenkins任務,Jenkins 2則通過使用Jenkins DSL和Groovy語言編寫程式,使用者可以定義流水線並執行各種任務。
這裡提到的DSL代表領域特定語言(Domain-Specific Language),可以理解為一種適用於Jenkins的程式語言。DSL基於Grovvy實現,並通過概念和結構封裝了Jenkins的特定功能。
Jenkins 2推薦使用名為Jenkinsfile的檔案儲存任務配置和流水線資訊,不同的專案和分支都會有自己的Jenkinsfile,其內容各不相同。你可以將全部程式碼寫在一個Jenkinsfile中,也可以通過共享庫的方式呼叫外部程式碼。
4. Jenkins 2.x 實現流水線的兩種語法
當我們通過Jenkins 2.x實現流水線時,有兩種不同的語法樣式:指令碼式語法(script syntax)和宣告式語法(declarative syntax)。
指令碼式語法(script syntax)是Jenkins最開始實現流水線即程式碼的方式,這是一種命令式風格,在以前版本的Jenkins中,流水線即程式碼大體就是Groovy指令碼,其中外掛部分針對Jenkins的DSL步驟。這種方式幾乎沒有結構上的約束,程式流程也基於Groovy語法結構實現。
這種模式現在被稱為指令碼式流水線。在指令碼式流水線中,DSL支援為數眾多的任務步驟,但是仍然缺失了部分面向Jenkins任務的核心特性,比如,構建後處理、流水線結構錯誤檢查以及基於不同執行狀態傳送通知的功能。當然大多數功能都可以通過Groovy程式設計機制來模擬實現,比如try-catch-finally語法。但是這在面向Jenkins程式設計的基礎上對Groovy語言技能提出了更高的要求。
而宣告式語法,是Jenkins提供的一種新的選擇,宣告式風格的流水線程式碼被編排在清晰的段落中,相對於只關注實現邏輯。
5. 如何選擇指令碼式語法或宣告式語法
那麼有哪些因素會影響選擇指令碼式語法或宣告式語法呢?和大多數事情一樣,這也不是一個嚴謹的科學問題。在特定的情況下,對比需求、實現的結構和流程以及構建流水線的人員技能和背景,二者可能各有千秋。
比如,指令碼式流水線具有以下優點:
- 更少的程式碼段落和弱規範要求。
- 更強大的程式程式碼能力。
- 更像編寫程式碼程式。
- 傳統的流水線即程式碼模型,使用者熟悉並向後相容性。
- 更靈活的自定義程式碼操作。
- 能夠構建更復雜的工作流和流水線。
但同時,指令碼式流水線也具有以下缺點:
- 普遍要求更高的程式設計水平。
- 語法檢查受限於Groovy語言及環境。
- 和傳統的Jenkins模型有很大差異。
- 與宣告式流水線的實現相比,同一工作流會更復雜。
看一則簡單的,指令碼式流水線示例:
node("worker_node1"){
stage("Source"){
//從Git倉庫中獲取程式碼
git 'git@github.com:zhoujinjian/intelligent-test-platform.git'
}
stage("Compile"){
//執行Gradle進行編譯和單元測試
sh "gradle clean comileJava test"
}
}
而宣告式流水線優點有:
- 更結構化,貼近傳統的Jenkins Web表單形式。
- 更強大的宣告內容能力,高可讀性。
- 可以能過Blue Ocean圖形化介面自動生成。
- 段落可對映到常見的Jenkins概念,比如通過。
- 更友好的語法檢查和錯誤識別。
- 提升流水線間的一致性。
但如此同時,宣告式流水線的缺點也很明顯:
- 對迭代邏輯支援較弱(相比程式而已)
- 對於傳統的Jenkins中部分功能缺乏支援。
- 更嚴格的結構。
- 目前對於複雜的流水線和工作流難以勝任。
宣告式流水線示例:
pipeline{
agent{
lable "worker_node1"
}
stages{
stage("Source"){
steps{
//從Git倉庫中獲取程式碼
git 'git@github.com:zhoujinjian/intelligent-test-platform.git'
}
}
stage("Compile"){
steps{
//執行Gradle進行編譯和單元測試
sh "gradle clean comileJava test"
}
}
}
}
簡而言之,對於新使用者和那些希望流水線具備傳統Jenkins一樣可讀性的使用者來說,宣告式流水線更容易學習和維護。指令碼式流水線更加靈活,允許使用者不受結構結束實現更多功能。
不過,總的來說,任何一種流水線型別對大多數場景而言同樣適用。好了本文作為CI持續整合系列的開篇,先介紹到這裡吧。
詳細可檢視:原文閱讀