天天看點

Jenkins 2 建立流水線

Jenkinsfile:

在Jenkins 2中,流水線配置可以從Jenkins中分離出來。在以前版本的Jenkins中,任務配置都是以配置檔案的形式儲存在Jenkins的主目錄中的。這就意味着所有的配置變更都依賴于Jenkins可以識别和管理這些檔案(除非你想直接修改XML檔案,但這是非常有挑戰性的事情)。在Jenkins 2中,你可以在Web可視化界面的文本區中以DSL腳本來編寫流水線配置。當然,你同樣可以将這些文本形式的DSL代碼和其他儲存源碼的文本檔案一起儲存在外部的版本控制系統中。這使得你可以像管理其他源碼一樣通過檔案的形式來管理Jenkins任務,支援曆史追溯、差異對比等功能。

Jenkins 2推薦使用名為Jenkinsfile的檔案儲存任務配置和流水線資訊。不同的項目和分支都會有自己的Jenkinsfile,其内容各不相同。你可以将全部代碼寫在一個Jenkinsfile中,也可以通過共享庫的方式調用外部代碼。另外,DSL語句也允許在腳本中加載外部代碼。

enkinsfile可以起到标記檔案(marker file)的作用,這意味着隻要Jenkins發現你的工程源碼中包含了Jenkinsfile檔案,那麼這個項目或分支就可以被Jenkins自動解析和運作。Jenkins同樣可以識别出需要用到的源碼版本控制管理(SCM)項目和分支,并加載和執行Jenkinsfile中的代碼。如果你熟悉Gradle建構工具,這個理念與應用中定義的build.gradle檔案類似。

Jenkins 2 建立流水線
Jenkins 2 建立流水線

新的任務類型和插件:

Jenkins 2 建立流水線

當選擇在Jenkins 2中建立一個新的工作項時,螢幕中會提示選擇建立任務的類型。你會看到一些熟悉的類型,比如,自由風格類型項目,同時還有一些你以前沒見過的類型

Jenkins 2 建立流水線

流水線:

顧名思義,流水線類型的項目旨在建立流水線。這是通過Jenkins DSL編寫代碼來實作的。流水線項目是我們在本書中主要讨論的項目類型。正如已經指出的,流水線既可以用“腳本式”文法風格編寫,也可以用“聲明式”文法風格編寫。這種項目類型的流水線可以很容易地轉換成Jenkinsfile。

檔案夾:

這是一種可以把多個項目歸類到一起的方式,而不是項目本身的類型。請注意,這并不像Jenkins儀表闆上傳統的“視圖”頁籤那樣,讓你按照項目清單篩選。更确切地說,它就像作業系統中的目錄檔案夾。檔案夾名稱是項目路徑的一部分。

組織:

有些源碼版本控制平台提供了将多個代碼庫聚合成“組織”的機制。Jenkins內建允許将Jenkins流水線腳本存儲為組織内代碼庫中的Jenkinsfile檔案,并基于這些庫執行。目前已經支援GitHub和Bitbucket平台的組織功能,未來将會逐漸支援其他的平台。為簡單起見,在本書中主要以GitHub的組織項目作為例子。假設有足夠的通路權限,Jenkins可以在代碼托管側自動建立一個組織的webhook(來自網站的通知),進而任何代碼庫中的變更都會通知Jenkins執行個體。當Jenkins收到通知時,它會檢測代碼庫中作為一種标記而使用的Jenkinsfile檔案,并執行其中的指令來運作流水線。

多分支流水線:

在這種類型的項目中,Jenkins再次使用Jenkinsfile作為标記的功能。在一個有Jenkinsfile的項目中,如果建立了一個新的分支,Jenkins将自動基于這個新分支建立一個新項目。此類型項目可應用于任何Git或SVN代碼庫。

新版本特性:

· 流水線被視為“一等公民”。這意味着流水線在應用程式中是作為實體被設計和支援的,而不是通過在Jenkins中連接配接一堆任務而形成流水線。

· 流水線可以通過編碼程式設計,而不是僅僅通過配置接口來描述。這就允許使用額外的邏輯和工作流,以及在傳統Jenkins中不可用或不存在的程式設計架構。

· 有專門用于流水線程式設計的結構化DSL。

· 流水線可以直接作為一個腳本在任務中建立,而不需要任何大量的Web表單互動。此外,它們可以完全在Jenkinsfile中單獨建立。

· 存儲為Jenkinsfile的流水線現在可獨立于Jenkins和源碼存儲在一起。

· DSL有在工作空間中輕松共享檔案的功能。

· 有更先進的、内置的使用Docker容器的支援。

當我們在Jenkins中編輯流水線時,有兩種不同的文法樣式:腳本式文法(scriptedsyntax)和聲明式文法(declarative syntax)。

腳本式文法(scriptedsyntax):

腳本式文法(scripted syntax)是Jenkins最開始實作的流水線即代碼方式。這是一種指令式風格,也就是在流水線腳本中定義邏輯和程式流程。它也更依賴于Groovy語言和結構,特别是對于錯誤檢查和異常處理來說。

聲明式文法(declarative syntax):

聲明式文法(declarative syntax)是Jenkins提供的一種新的選擇。聲明式風格的流水線代碼被編排在清晰的段落中,相對于隻關注實作邏輯,這些流水線的主要區域描述(或“聲明”)了我們所期望的流水線的狀态和輸出。在下面的代碼示例中,上面是腳本式文法,下面是對應的聲明式文法。

Jenkins 2 建立流水線

腳本式流水線更像是一種腳本或程式設計語言,像其他指令式語言一樣可以運作程式和處理邏輯,而聲明式流水線則更像Jenkins的傳統實作方式,在Web表單的預定義字段中輸入關鍵資訊,代表了特定目标和預期行為。與傳統的Web表單類似,當執行聲明式流水線時,每一個段落定義了基于使用者輸入資料的執行内容和方式。

我們可以通過分析每種類型的優缺點,擷取普遍規律和一些參考指導。

簡而言之,腳本式流水線具有以下優點:

· 更少的代碼段落和弱規範要求。

· 更強大的程式代碼能力。

· 更像編寫代碼程式。

· 傳統的流水線即代碼模型,使用者熟悉并向後相容性。

· 更靈活的自定義代碼操作。

· 能夠建構更複雜的工作流和流水線。

腳本式流水線具有以下缺點:

· 普遍要求更高的程式設計水準。

· 文法檢查受限于Groovy語言及環境。

· 和傳統Jenkins模型有很大差異。

· 與聲明式流水線的實作相比,同一工作流會更複雜。

聲明式流水線具有以下優點:

· 更結構化,貼近傳統的Jenkins Web表單形式。

· 更強大的聲明内容能力,高可讀性。

· 可以通過Blue Ocean圖形化界面自動生成。

· 段落可映射到常見的Jenkins概念,比如通知。

· 更友好的文法檢查和錯誤識别。

· 提升流水線間的一緻性。聲明式流水線具有以下缺點。

· 對疊代邏輯支援較弱(相比程式而言)。

· 仍在開發完善中(對于傳統Jenkins中的部分功能缺乏支援)。

· 更嚴格的結構(更難實作自定義流水線代碼)。

· 目前對于複雜的流水線和工作流難以勝任。

簡而言之,對于新使用者和那些希望流水線具備傳統Jenkins一樣可讀性的使用者來說,聲明式流水線更容易學習和維護。這是以靈活性為代價換取結構不支援的功能。腳本式流水線更加靈活,提供了“超級使用者”的選項,即允許使用者不受結構限制實作更多功能。不過,總的來說,任何一種流水線類型對大多數場景而言都同樣适用。

系統(system):主節點(master)、節點(node)、代理節點(agent)和執行器(executor)

… 不管我們使用腳本式文法還是聲明式文法,每條Jenkins流水線都必須具備一個或多個系統用于執行代碼。術語系統(system)在這裡作為一種通用方法描述了我們所有需要讨論到的項目(item)。請記住,在任何給定的系統或機器上都可能運作着多個Jenkins執行個體。

…在傳統Jenkins中隻有兩類節點:主節點(master)和從節點(slave),你可能已經非常熟悉這些概念了。下面是對一些相似概念的描述,主要為了對比突出差異點。

主節點:

…Jenkins主節點是一個Jenkins執行個體(instance)的主要控制系統。它能夠完全通路所有Jenkins配置選項和任務(job)清單。如果沒有指定其他系統(system),它也是預設的任務執行節點。不過并不推薦在主節點上執行高負載任務,任何需要大量處理的任務都應該在主節點之外的系統上運作。這樣做的另一個原因是,凡是在主節點上執行的任務,都有權限通路所有的資料、配置和操作,這會構成潛在的安全風險。同樣值得注意的是,在主系統上不應該執行任何包含潛在阻塞的操作,因為主系統需要持續響應和管理各類操作過程。

節點:

… 在Jenkins 2中,節點是一個基礎概念,代表了任何可以執行Jenkins任務的系統。節點中包含主節點和代理節點,有的時候也用于指代這些概念。此外,節點也可以是一個容器,比如Docker。在任何Jenkins執行個體中主節點都會存在,但是由于上述原因,我們并不推薦在主節點上執行任務。

代理節點:

… 在早先版本的Jenkins中,代理節點被稱為從節點(slave),其代表了所有非主節點的系統。這類系統由主系統管理,按需配置設定或指定執行特定的任務。例如,我們可以配置設定不同的代理節點針對不同的作業系統建構任務,或者可以配置設定多個代理節點并發地運作測試任務。為了減少系統負載,降低安全風險,通常在子系統上隻會安裝一個輕量級的Jenkins用戶端應用來處理任務,這個用戶端應用對資源通路是受限的。随着代理節點和節點之間關系的演進,代理節點在節點上運作。在腳本式流水線中,“節點”特指一個運作代理節點的系統,而在聲明式流水線中,其指代一個特定的代理節點來配置設定節點。

指令與步驟:

… 根據節點和代理節點在聲明式文法和腳本式文法中的使用方式,我們可以得出這兩個概念之間的高層次的差異。node用于腳本式流水線,從技術層面上看它是一個步驟,代表可以用于流水線中執行活動的資源。它在一個運作代理節點的節點上面配置設定一個執行器,并進一步在定義的代碼塊上運作代碼。下面的代碼片段展示了一個指定node步驟的簡單示例:

Jenkins 2 建立流水線

而相對于聲明式流水線中的agent,它作為一個指令用來配置設定節點,除非使用了特殊用法agent none。下面是一個簡單的agent聲明的示例:

Jenkins 2 建立流水線

執行器:

…執行器同上述所有系統都有關系。讓我們來看看Jenkins如何定義這個術語。簡單地說,執行器隻是節點/代理節點用于執行任務的一個插槽。一個節點可以有任意多個執行器。執行器的數量定義了該節點可以執行的并發任務數量。當主節點将任務配置設定給特定節點時,該節點上必須有可用的執行器插槽來立即執行該任務,否則任務會一直處于等待狀态,直到一個執行器變為可用。執行器的數量和其他參數可以在建立節點的時候進行配置,後面會介紹這一主題。

Jenkins 2 建立流水線

建立節點:

在傳統版本的Jenkins中,任務可以在主節點執行個體或者從節點執行個體上執行。在Jenkins 2的術語中,這些執行個體被統一成通用術語“節點”。建立新節點和過去添加從節點的方法是完全一樣的。下面是一個簡單的示例。

Jenkins 2 建立流水線

在管理節點界面中,選擇新節點并填寫表單,包括執行器數量:

Jenkins 2 建立流水線

在管理節點界面中,選擇新節點并填寫表單,包括執行器數量:

Jenkins 2 建立流水線
Jenkins 2 建立流水線

注意,在界面底部有環境變量和工具路徑兩個複選框。勾選這些複選框可以為該節點定義特殊變量和工具。隻有當你希望使用與主節點不同的配置時,才會用到這些複選框;

标簽可以滿足系統和使用者的不同需求,比如可以用于以下場景。

· 識别一個特定的節點(通過一個專有标簽)。

· 對一類節點進行分組(通過配置設定相同的标簽)。

· 識别節點的特征,友善使用(通過一個有意義的标簽,比如“Windows”或者“West Coast”)。上面的最後一個場景是推薦場景。

更多關于不同啟動方法和節點配置的資訊,請檢視Jenkins線上文檔。一旦節點準備就緒,我們就可以專注于建立流水線了。我們将通過Jenkins DSL結構化程式來實作這一點。

Jenkins DSL和Groovy語言:

Jenkins流水線的DSL基于Groovy語言實作。這意味着我們可以按照需求在流水線中使用Groovy語言的結構和習慣用法。但在通常情況下,我們傾向于避免使用過于複雜的Groovy代碼,或者至少将其與主腳本分開。這樣做的原因是,使用過多的Groovy代碼會降低腳本的可讀性和可維護性,尤其是對那些不了解Groovy的人來說。聲明式流水線禁止使用定義結構之外幾乎所有的Groovy代碼,并且還提供了更多類似于傳統Jenkins特性的功能,是以你必須盡量減少使用自定義Groovy代碼。

下面是一個非常簡單的Jenkins DSL流水線表達式:

Jenkins 2 建立流水線

節點:

…節點在管理Jenkins→管理節點界面中定義,操作方法和之前添加從節點的方法完全一緻。每一個節點都會自動安裝Jenkins代理節點來執行任務(注意,這裡假設在Jenkins執行個體中已經添加了一個節點,并打上了worker1标簽):

節點和代理節點:

…在之前的Jenkins術語部分,我們已經介紹了節點和代理節點的差別。在這一部分中,代理節點特指在“非主節點”上運作Jenkins代碼。這一行告訴Jenkins應該在哪個節點上運作這部分流水線。它将代碼與節點上運作的Jenkins代理程式綁定起來。通過将定義的名稱作為參數(标簽)傳遞進來指定特定節點。這個節點或系統必須已被定義,并且Jenkins系統知曉它的存在。在這裡你可以選擇不提供标簽,但是如果忽略标簽,則需要了解它的運作機制。

· 如果master被配置為預設的執行節點,那麼Jenkins會在master上執行任務(可以配置master為不執行任何任務)。

· 否則,節點标簽為空(或者在聲明式文法中使用agent any),Jenkins會在任意節點上找到第一個可用的執行器來執行任務。換言之,如果在這裡指定多個名稱(使用邏輯運算符)也是完全有效的,尤其當你需要基于多個次元來選擇節點的時候(如地點、類型等)很有意義。下面的擴充内容介紹了如何使用這項功能。

為一個節點打多重标簽:

你可以使用标準的邏輯運算符來指定多個标簽,比如,“||”表示或,“&&”表示與:

為什麼要這麼做呢?假設你分别在美國的東西海岸擁有兩套Linux系統。基于某些特定的操作場景,你可能希望某些Jenkins任務被發送到東海岸,而另一些則在西海岸執行。

那麼在這個場景中,你可以為所有節點添加Linux标簽,同時附加一個新的标簽來表示所在地域,如east或west。一旦标簽就緒,你就可以通過操作符和标簽的組合來指定節點。例如,一個任務需要在東海岸的Linux節點執行,可以這樣描述:

Jenkins 2 建立流水線

這種大括号結構({})被稱為Groovy閉包,标記了流水線中與該節點關聯的代碼起止段落。閉包也類似于程式中傳遞的實體,最後一個語句代表了傳回值。(請參閱Groovy文檔以擷取更多關于閉包的資訊。)

節點和映射:

除了定義節點來執行指定階段任務,節點還可以通過映射指定其他部分代碼的執行位置,比如,下面是一個parallel結構的示例:

Jenkins 2 建立流水線

階段:

…在節點的定義中,我們可以将個人設定、DSL指令和邏輯組合在一個stage閉包中。階段必須指定一個name,這提供了一種機制,可以用來描述這個階段的職責。現有的階段實質上并沒有在腳本中做什麼事情,僅在運作流水線時在輸出中辨別出這個階段的位置。研發人員可以決定在一個特定階段中包含多少流水線邏輯。然而,一個通用的實踐是建立階段來模仿傳統流水線中的任務片段。例如,我們可以設計一個階段來擷取源碼,一個階段來編譯源碼,一個階段來執行單元測試,一個階段來執行內建測試等.

步驟:

…階段中包含了實際的Jenkins DSL指令,這在Jenkins術語中被稱為步驟(step)。一個步驟是DSL定義中最基本的功能。它雖然不是Groovy指令,但是可以和Groovy指令搭配使用。在以下示例中,我們通過初始步驟來擷取源碼:

Jenkins 2 建立流水線

這種文法非常簡單易懂,調用git指令并傳遞給它拉取代碼的位址參數(使用安全的HTTP協定)。對完整的步驟文法而言,這是一種縮寫格式。當在腳本中使用DSL時,步驟的縮寫格式和完整格式文法都會碰到,是以有必要花點時間來更好地了解文法模型的細節。

了解步驟文法:

Jenkins DSL中的步驟總是期望映射(命名)參數。為了說明這一點,下面有另一個版本的git步驟的定義:

Jenkins 2 建立流水線

請注意,在這裡有兩個命名參數,其映射到期望的值:branch等于’test’,url等于:

Jenkins 2 建立流水線

實際上,這種文法本身是Groovy所使用的映射文法的一種簡寫形式。[命名參數:value,命名參數:value]等同于[key: value, key: value]的Groovy映射文法。其中命名參數函數作為映射的關鍵字。

Groovy還允許跳過參數的圓括号。如果沒有這些快捷方式,較長版本的步驟将是這樣的:

Jenkins 2 建立流水線

在本例中隻有url參數是必選參數。如果沒有命名參數,那麼預設的參數就是script對象。下面的示例是一個bat步驟,在Windows系統上運作批處理或shell腳本。按照标準完整版文法,指令類似如下:

Jenkins 2 建立流水線

這個指令可以簡寫:

Jenkins 2 建立流水線
Jenkins 2 建立流水線

現在我們已經了解了腳本式流水線的基本結構,接下來讓我們建立一個Jenkins流水線任務,并使用相關工具建立一個腳本:

…不管是哪個版本的Jenkins,我們都是通過建立一個指定類型的項目來開始一個新項目的。Jenkins 2内置了流水線類型的項目支援。這種類型的項目提供了編寫代碼來定義流水線的環境。在剛開始接觸這類項目的時候,了解如何配置和使用環境建立、編輯、運作和監控流水線是很有幫助的。Jenkins的流水線腳本既可以在流水線類型的Jenkins任務中建立,也可以定義在一個叫作Jenkinsfile的外部檔案中。Jenkinsfile可以同代碼儲存在一起。我們會采用在流水線任務中建立腳本的方式來學習建立DSL腳本。Jenkinsfile可以在任何文本編輯器中建立,當然也可以從流水線任務中複制生成。然而,在調用外部資源等任務時,流水線也需要進行相關調整。

Jenkins 2 建立流水線