Pipeline 簡介
Jenkins2.x 的核心是使用 pipeline 來建構項目,也就是流水線,将 Jenkins1.0 版本中基于表單的配置資訊比如 JDK/SVN 以及參數的配置都轉變成了代碼,即 pipeline as Code。
傳統的表單方式有以下缺點:
需要大量的 web 表單互動,有時候需要進行很多次的切換,比較繁瑣。
不能進行版本管理。
可重用性差。
而采用 pipeline 的方式,項目的所有流程和配置都寫在 Jenkinsfile 檔案中,移植時隻要将此檔案拷貝即可,無須繁瑣的配置;而且 pipeline 可以很直覺的看到每個階段的建構情況,再結合上 Blue Ocean 可以進行強大的流水線監控,友善、直覺、及時地擷取到建構結果。
在 Jenkins 中,把每一段管道比作是不同的 Job,不同 Job 的連結就需要用到 Pipeline 插件。Jenkins 的工作流程可以簡單概括為 build-deploy-test-release,每個流程之間我們都可以用 Pipeline 來連接配接,大緻如下效果圖:

Jenkins pipeline 是基于 Groovy 語言實作的一種 DSL(Domain-Specific Language,領域特定語言),可以了解為适用于 Jenkins 的程式設計語言。
pipeline 支援兩種文法:腳本式文法(scripted pipeline)和聲明式文法(declarativepipeline)。早期的 pipeline plugin 隻支援腳本式文法,聲明式文法是在 pipeline2.5 之後新增加的,相對而言,聲明式文法更簡單,即使沒有 groovy 語言的基礎也能進行基本的操作。Jenkins 社群的動向也是偏向于聲明式文法,是以以聲明式文法為例進行說明。
Pipeline 基本結構
以上是最最基本的一個 pipeline 結構,具體的含義如下:
pipeline:後面用一對 {} 也就是閉包,表示整條流水線,裡面是流水線中具體的處理流程。
agent:用來指定整個流水線或者某一個階段在哪個機器節點上執行。如果是 any 的話表示該流水線或者階段可以運作在任意一個定義好的節點上。這個指令必須要有,而且一般會放在頂層 pipeline{...} 的下一層,在 stage{...} 中也可以使用 agent,但是一般不這麼用。
stages:後面跟一對 {},類似于一個容器,封裝了一個或多個 stage,也就是将不同的階段組織在一起;例如 build 是一個 stage, test 是第二個 stage,deploy 是第三個 stage。通過 stage 隔離,讓 Pipeline 代碼讀寫非常直覺。
stage:後面跟一對 {},流水線中的某個階段,其中封裝了多個執行步驟,每個階段都需要有個名稱。
steps:封裝了在一個階段中的一個或多個具體的執行步驟。在本例中 echo 就是一個步驟。
接下來我們一一介紹上面提到的 pipeline 中包含的最基本的幾個 section,以及另外一些可選的 section。
agent
用來指定 pipeline 的執行節點,一般放在頂層的 pipeline 中。agent 部分支援幾種不同的參數以此來适應不同的應用場景。
作用:表示可以在任意的節點或者代理上執行此 pipeline。
代碼示例:
作用:在 pipeline 的頂層應用中使用此參數的話表示不會為整個 pipeline 指定執行的節點,需要在每個 stage 部分用 pipeline 指定執行的節點。
作用:在标簽指定的可用代理上執行 pipeline 或 stage,比如 agent {label "label"} 表示流水線或者階段可以運作在任何一個具有 label 标簽的代理節點上。
作用:代理節點的标簽新增了一個特性,允許為流水線或階段指定一個自定義的工作空間,用 customWorkspace 指令來指定。和 label 功能類似。
此處的 node 可以換成 label,但是為了避免 Docker 代理節點中的 label 用法混淆,一般用 node 表示。這種類型的 agent 在實際工作中的使用場景是最多的。
可以将以上代碼段放到 Jenkinsfile 中或者在 Jenkins ui 中去執行。
POST
post 部分用來指定 pipeline 或者 stage 執行完畢後的一些操作,比如發送郵件、環境清理等。post 部分在 Jenkins 代碼中是可選的,可以放到頂層,也就是和 agent 同級,也可以放到stage 中。在 post 代碼塊中支援多種指令,比如:always、success、failure、aborted、unstable、changed 等等,我們一一來介紹。
作用:當 pipeline 執行完畢後一定會執行的操作,不管成功還是還失敗。比如說檔案句柄的關閉或者資料庫的清理工作等。
作用:當 pipeline 執行完畢後且建構結果為成功狀态時才會執行的操作。
作用:當 pipeline 執行完畢後且建構結果為失敗時執行的操作,比如發送錯誤日志給相關人員。
作用:當 pipeline 執行完畢後且建構狀态和之前不一緻時執行的操作。
作用:當 pipeline 被手動終止時執行的操作。
作用:當 pipeline 建構結果不穩定時執行的操作。
在 post 部分是可以包含多個條件塊,也就是以上指令的組合,比如:
stages/stage/steps
stages:Pipeline 中單個階段的操作封裝到 stages 中,stages 中可以包含多個 stage。
stage:一個單獨的階段,實際上所有實際工作都将包含在一個或多個 stage 指令中。stage{…} 裡面有一個強制的字元串參數,用來描述這個 stage 的作用,這個字元串參數是不支援變量的,隻能你自己取名一個描述字段。
steps:一個 stage 下至少有一個 steps,一般也就是一個 steps。可以在 steps 下寫調用一個或者幾個方法,也就是兩三行代碼。
有以下注意點:
在聲明式 pipeline 腳本中,有且隻有一個 stages。
一個 stage{…} 必須有且隻有一個 steps{…}, 或者 parallel{…} 或者 stages {…},多層嵌套隻支援在最後一個 stage{…} 裡面。
在聲明式文法中隻支援 steps,不支援在 steps {…} 裡面嵌套寫 step{…}。
代碼示例:
environment
作用:通過鍵值對的方式定義整個 pipeline 或者 stage 中使用的環境變量。
options
options 指令在 pipeline 也是可選的。用來指定一些屬性和值,這些預定義的選項可以應用到整個流水線中,可以了解為在 Jenkins web 表單裡一個項目的基本配置中定義的事情。
作用:表示 Jenkins 中的 job 執行失敗後繼續進行幾次嘗試。可以放到頂層的 pipeline 中也可以放到 stage 中。注意:這個次數是指總次數,包括第 1 次失敗。
作用:保留指定數量的流水線執行,包含控制台輸出以及制品。當 pipeline 指定完畢後,會在工作空間中儲存制品和執行日志,如果執行次數太多的會話,這些内容會占用很多的存儲空間,使用該參數後會隻保留最近指定次數的建構結果,自動清理之前的内容。
說明:logRotator 元素并沒有什麼作用,主要是曆史原因。
作用:指定檢出到工作空間的子目錄中。Jenkins 從代碼管理庫中拉取代碼時預設檢出到工作空間的根目錄,如果想修改的話可以用此參數。
作用:阻止 pipeline 同時執行。預設的情況下 pipeline 是可以同時執行多次的,如果為了防止同時通路共享資源或者防止一個較快的并發執行把較慢的并發執行給碾壓的場景可以使用此參數禁止并發執行。
作用:為流水線的執行設定一個逾時時間。如果超過這個值就會把整個流水線終止。時間機關可以是 SECONDS(秒),MINUTES(分鐘),HOURS(小時)。
作用:删除隐式的 checkout scm 語句,是以可以從 Jenkinsfile 定義的流水線中跳過自動的源碼檢出功能。
parameters
parameters 用來在 pipeline 中實作參數化建構,也就是根據使用者指定的不同參數執行不同的操作。pipeline 支援很多種類型的參數,有字元串參數,布爾選擇參數,下拉多選參數等。
作用:開始建構前需要使用者輸入字元串,比如 ip 或者 url。
作用:定義一個布爾類型參數,在執行建構前使用者在 Jenkins UI 上選擇是還是否,選擇是執行這部分代碼,否則會跳過這部分。比如:執行完畢後環境的清理工作。
作用:支援寫很多行的字元串。
作用:支援使用者從多個選擇項中選擇一個值用來表示這個變量的值。比如:選擇伺服器類型、選擇版本号等。
作用:參數化建構 UI 上提供一個檔案路徑的輸入框,Jenkins 會自動去根據使用者提供的網絡路徑去查找并下載下傳。
作用:密碼(password)參數就是在 Jenkins 參數化建構 UI 提供一個暗文密碼輸入框。
例如,需要登入到伺服器做自動化操作,為了安全起見,就不能用名為的 string 類型參數,而是 password 方式。
注意:
儲存之後,左側菜仍然單是 Build now,而并不是 Build with Parameters,這個是正常的,需要先點選 Build now,先完成第一個建構,Jenkins 第二個建構才會顯示代碼中的三個參數。重新整理之後,就可以看到參數化建構這個菜單。
tool
作用:定義自動安裝和放置工具的路徑。
對于 agent none,這個關鍵字将被忽略,因為沒有任何節點或者代理可以用來安裝工具。此指令主要是為了三大工具(jdk、gradle、maven)提供環境變量服務。一旦配置完成,tools 指令可以讓我們指定的工具需要在我們已經選擇的代理節點上自動安裝在配置路徑下。
說明:
左側的 jdk 是流水線模型中定義的特殊字元串,目前,在聲明式流水線中可以指定的合法的工具類型如下:ant、git、gradle、jdk、maven、jgit 等。
右側的 jdk8 映射的是全局工具配置中的名稱字段(管理 Jenkins → Global ToolConfiguration 中預配置)。例如,上面代碼我寫了 jdk1.8,那麼必須在 Jenkins 管理-->全局工具配置中有别名為 jdk1.8 配置。
一旦這樣設定後,jdk 工具會被自動安裝到指定的路徑下,然後我們可以在流水線步驟中簡單的使用 jdk1.8 字元串替代 JAVA_HOME 路徑,Jenkins 會把它映射到我們系統中安裝的 JDK。
說明:如果需要輸入一個特定的版本來使用,這個 tools 指令可以使用一個參數的值。
注意:目前生命式文法有一個局限就是當這個流水線第一次運作時,Jenkins 不能識别出該建構需要一個參數,需要先手動建構一次。
when
when{…} 是寫在 stage{…} 裡面一層條件控制,允許 pipeline 根據給定的條件來決定是否執行某個階段。when 指令必須至少包含一個條件,也可以含多個條件,這與子條件嵌套在一個 allOf 條件中一樣。
更複雜的條件結構可使用嵌套條件建:not,allOf 或 anyOf,嵌套條件可以嵌套到任意深度。下面來看看 when{…} 支援的一些内置條件指令。
作用:當正在建構的分支與給出的分支模式比對時執行。注意,僅适用于多分支 pipeline。
作用:當指定的環境變量與給定的值相同時執行。
作用:當給定的 Groovy 表達式傳回 true 時執行。
作用:當嵌套條件為 false 時執行,必須包含一個條件。
作用:當所有嵌套條件都為真時執行,必須至少包含一個條件。
作用:當至少一個嵌套條件為真時執行,必須至少包含一個條件。
作用:如果 pipeline 所執行的暧昧被打了 tag 則執行。
environment 裡面定義了一個鍵值對“quick_test = false”, 第二個 stage('ExampleDeploy') 因為不滿足 when{…}裡面的條件就不會執行。
script
作用:用來在聲明式流水線中寫非聲明式代碼的地方,允許你定義一定代碼塊/閉包用來囊括非聲明式的文法,其實就是在 script 中寫 Groovy 代碼。比如 if...else 等語句。
triggers
用來指定使用什麼類型的觸發器來自動啟動流水線建構。注意:這些觸發器并不适合用于多分支流水線、github 組織等類型的任務。我們介紹 4 種不同的觸發器:cron、pollSCM、upstream 以 githubPush。
作用:按照指定的周期有規律的執行流水線,就是鬧鐘一樣,一到時間點就執行。
cron 包含 5 個字段,這些字段以空格或者 Tab 鍵分割,用來指定多久去執行一次建構。格式為:
MINUTES:一小時内的分鐘,取值範圍(0-59)
HOURS:一天内的小時,取值範圍(0-23)
DAYMONTH :一個月中的某一天,取值範圍(1-31)
MONTH :月份,取值範圍(1-12)
DAYWEEK:一周中的星期幾,取值範圍(0-7)。0 和 7 都表示星期日
還可以使用特殊的字元一次指定多個值:
*:比對所有的值
N:比對 M-N 之間的值
M-N/
A,B,...Z:多個枚舉值
H:可以用于任何字段,用來告訴 Jenkins 在一個範圍内使用該項目名的散列值計算出一個唯一的偏移量,這個偏移量于範圍内的最小值相加後定義為實際的執行時間。注意:這個值是項目名的散列值,那麼每一個值都與其他項目是不同的,但是同一個項目的值是不變的。
H 符号在實際的項目中是非常推薦使用的,因為在大型的項目中可能存在多個同一時刻需要執行任務,比如(0 0 * * *),都需要在半夜零點啟動,那麼使用 H 後,從雜湊演算法獲得的偏移量,就可以錯開執行具有相同 cron 時間的項目。
作用:由上遊的任務建構完畢後觸發本任務的執行。比如說需要先執行完編譯打包和釋出後才能執行測試腳本。
upstreamProjects:指定上遊任務的名稱,有多個任務時用逗号分隔 。
threshold:指定上遊任務的執行結果是什麼值時觸發,是枚舉類型 hudson.model.Result 的某一個值,包括:
SUCCESS:建構成功;
UNSTABLE:存在一些錯誤,但不至于建構失敗;
FAILURE:建構失敗。
注意:需要手動觸發一次 pipeline 的執行,讓 Jenkins 加載 pipeline 後,trigger 指令才會生效。
作用:輪詢代碼倉庫,也就是定期到代碼倉庫詢問代碼是否有變化,如果有變化就執行。文法和 cron 是一樣的。理論上輪詢的越頻繁越好,但是在一定的建構時間内,如果有多次代碼送出,當建構失敗時無法馬上知道是哪一次的送出導緻的,是以這個指令不是很常用,一般是用 webhook,當有代碼送出的時候主動通知到 Jenkins。
需要安裝 Generic Webhook Trigger(簡稱 GWT)插件才能使用,安裝方式見 3.3 節。安裝完之後,Jenkins 會暴露一個 API:http://者 XML 的 HTTP POST 請求後,根據請求的參數和 Jenkins 中項目的比對情況來決定執行哪個 Jenkins 項目。注意:項目建立完成後,一定要手動執行一次,這樣 pipeline 的觸發條件才會生效。
代碼格式:
總結起來可以分為 5 部分:
genericVariables/genericHeaderVariables/genericRequestVariables:從 HTTP POST 請求提取參數。
token:用于辨別待觸發的 Jenkins 項目。
regexpFilterExpression/regexpFilterText:根據請求參數判斷是否觸發 Jenkins 項目的執行。
printContributedVariables/printPostContent/causeString:日志列印控制。
webhook:響應控制。
genericVariables:提取 POST body 中的請求參數。
用法:
expressionType: 可選,'XPath'預設是 JSONPath,采用預設值的話不會有此參數,還可以設定為 XPath。
value:JSON 表達式或者 XPath 表達式,取決于 expressionType 的類型。
key:一個變量名,用來存儲從 POST body 提取出的值,可以用于 pipeline 其它步驟。
defaultValue:可選,當沒有提取到時使用此值傳回。
regexpFilter:可選,過濾表達式,用來對提取出的值進行過濾。
genericHeaderVariables:從 URL 中提取參數
用法: genericHeaderVariables: [[key: 'header', regexpFilter: '']]
key:一個變量名,用來存儲從 URL 提取出的值,可以用于 pipeline 其它步驟。
regexpFilter:對提取出的值進行過濾。
genericRequestVariables:從 HTTP Header 中提取參數。和 genericHeaderVariables 用法類似。
用法: token: 'secret'
說 明 : 用 來 标 識 一 個 pipeline 在 Jenkins 中 的 唯 一 性 。 當 Jenkins 接 收 到generic-webhook-trigger/invoke 接口的請求時,會将請求傳遞給 GWT 插件,GWT 插
件内部會周遊 Jenkins 中所有的項目,找到 Generic Webhook Trigger 配置 token 和請求中相同 token 的項目,觸發這些項目的執行。
如果配置了以下 2 項,即使 token 值比對了,還要繼續判斷以下條件是否滿足,才能真正觸發項目的執行。
regexpFilterExpression:正規表達式。
regexpFilterText:需要比對的 key。
printContributedVariables:布爾類型,列印提取後的變量和變量值。
printPostContent:布爾類型,列印 webhook 請求資訊。
causeString:字元串類型,用來表示 pipeline 被觸發執行的原因,一般引用直接提取的變量。
共享庫
當 Jenkins 上建立很多個 pipeline 項目的時候,就會有一些公共的代碼在每個項目中都要去重複的編寫,當這些代碼需要做一些擴充或者修改的時候就需要把所有項目中全部改一遍,維護的成本太高,編寫的效率太低。比如發送郵件的功能是所有項目都需要的,郵件模闆都寫在每個 pipeline 項目中的話視覺效果極差。可以使用 pipeline 共享庫(shared library)的技術解決這一問題。
共享庫有 3 個部分組成:resources 目錄、src 目錄和 vars 目錄。示例如下:
resources 目錄:一般将非 groovy 檔案存放在此目錄中,比如 XML 檔案或者 JSON檔案,可以通過外部庫中的 libraryResource 步驟加載。
src 目錄:是使用标準 java 目錄結構的 groovy 檔案,目錄中的類稱為庫類(Library class),這些類必須實作 Serializable 接口,以此保證在流水線停止或者重新啟動時能正确的恢複。在流水線中使用 src 目錄中的類時,需要注意要使用包名,同時因為是 groovy 代碼,是以還要用 script 指令包起來。
vars 目錄:這個是我們要介紹的重點。此目錄下存放的可以在 pipeline 中直接調用的全局變量,在 pipeline 中使用的函數名就是檔案名,當檔案中定義了 call 方法時,它可以像正常流水線步驟一樣被調用。這個call方法就相當于這個公共方法的main方法。記住一個原則,一個公共方法,寫一個 groovy 類檔案,這個 groovy 檔案的名稱就是這個公共方法的函數名稱,在其他 pipeline 項目中調用這個方法就是直接寫這個groovy 類名稱。
共享庫的定義和使用一般分為以下 4 步:
根據工作實際需要編寫共享庫的源代碼;
将源代碼放到代碼管理倉庫中;
在 Jenkins 全局配置中定義共享庫;
在 pipeline 項目或中 Jenkinsfile 中通過@Library 引用共享庫。
注意:庫檔案中包含中文的話一定要儲存為 ANSI 格式,否則可能會出現亂碼的情況。
我們主要将常用的一些功能封裝到 vars 目錄來示範,其它進階的用法可以根據實際的需要進一步研究。在 vars 目錄下建立 2 個檔案,分别名為 command.groovy 的檔案,如下:
再建立名為 say.groovy 的檔案,内容如下:
在 pipeline 的上方使用@Library 引入共享庫。
文法:@Library('
libname:表示庫名,必須要有。
version:版本号以@開頭,可以是代碼倉庫的标簽、分支名或者其他規範。
_:下劃線,表示一次性靜态加載 src 目錄下所有的代碼到 classpath 中,如果沒有後面的 import 語句,就必須有此下劃線。
import:可以沒有,表示導入指定的方法,如果沒有指定表示導入共享庫中所有的方法。
使用示例:
Pipeline Basic Steps 插件用法
pipeline basic steps 是 pipeline 最基礎的一個插件,在安裝 pipeline 的時候預設會自動安裝,可以在 Jenkins 環境,插件管理下的 installed 下面找到這個插件。
作用:讀取指定檔案的内容,以字元串的形式傳回。
參數說明:
file:相對于目前工作空間的檔案路徑,也可以用絕對路徑表示;
encoding:讀取檔案時的編碼方式,預設是根據你目前平台的編碼去解析。如果讀取的是二進制檔案,會采用 Base64 轉碼的字元串輸出。
說明:将 jobs/test_pipeline_demo 目錄下的 demo.txt 檔案内容讀出并列印。
作用:writeFile 和 readFile 類似,是簡單的文本檔案進行寫操作。如果明确知道是 json 或其他類型檔案,那麼就可以用其他插件的 readJson 來讀取。
file:相對于目前工作空間的檔案路徑,也可以用絕對路徑表示,路徑不存在會建立。
text:要寫入的檔案内容。
encoding:寫入檔案時的編碼方式,預設使用的是目前平台的編碼。
作用:預設遞歸删除 WORKSPACE 下的檔案和檔案夾,這個方法是沒有參數,一般與 dir 一起使用。當執行完每一個 stage 裡面的代碼,需要在 post{...}裡面寫一些 clean up 操作,如果這個操作是清空 WORKSPACE 的話,就可以使用 deleteDir()。特别是生産環境,需要節約 Jenkins 伺服器的磁盤空間,清空 WORKSPACE 是很有必要的操作。
用法:deleteDir()
郵件功能在 Jenkins 中是非常有用的,當建構完成後無論成功還是失敗都需要将建構結果通知到相關人員,郵件是最常見的選擇。在 pipeline 中發送郵件之前,需要先按照 3.3.7 部配置設定置完畢。我們可以借助片段生成器檢視該插件支援的參數:
需要注意的是 Body MIME Type 這個選項預設就是 text/plain,可以指定為 text/html。
作用:切換操作目錄。
作用:echo和 groovy 中的 println 沒有任何差別。一般來說使用 echo 就是列印 info debug級别的日志輸出用,如果遇到錯誤,就可以使用 error(“error message”),如果出現執行到 error 方法,Jenkins job 會退出并顯示失敗效果。
作用:判斷一個檔案是否存在,傳回值是布爾類型,true 就表示檔案存在,false 表示檔案不存在。
作用:判斷目前運作的 Jenkins node 環境是 linux 還是 windows,如果傳回是 true 表示是 linux/mac 系統,如果傳回是 false,表示目前 Jenkins job 運作在 windows 的系統上。
作用:傳回目前所在的目錄。由于 Jenkins 支援 windows 和 linux,但是 linux 是 pwd,windows 上是 dir。是以這個插件就幹脆支援一個方法,統稱為 pwd()。
git plugin 插件用法
作用:使用 git 指令 checkout 出項目的代碼,在 pipeline 代碼中,很常見在不同 stage 中使用不同 git 倉庫位址的代碼,是以 git SCM 操作,可以寫在不同 stage 中。
publish html report 插件用法
作用:将測試完成後生成的 html 格式的測試報告展示在 Jenkins 中,無需再切換到目錄用浏覽器打開。
插件參數說明:
reportDir:項目中儲存 html 檔案的地方,這裡寫的是一個相對路徑寫法,相對于目前工作目錄的路徑,不寫的話預設是項目根目錄。
reportFiles:需要展示的 html 檔案名,也可以同時寫多個 html 檔案,逗号隔開。
reportName:這個參數指定的字元串會在 Jenkins 建構 Job 頁面顯示的菜單名稱,後面會看到這個名稱,這個名稱可以随意修改。
建構結果:
手動建構後,在項目首頁左側的導航欄可以看到上一步 reportName 值指定的菜單名:
單擊接口測試報告,可以看到如下展示結果:
借助 Jenkins 生成 pipeline 代碼
通過之前的介紹我們對 pipeline 常用的文法有了初步的印象,但是如果完全記住所有的指令還有第 3 方插件的指令也是不太現實的事情。其實 Jenkins 為我們提供了流水線文法線上生成的功能,我們基于表單的格式填好後,會 Jenkins 會幫助我們生成 pipeline 的代碼。
1)進入任意一個 pipeline 項目,單擊配置選項:
2)進入流水線頁籤,單擊左下角的流水線文法:
3)選擇“片段生成器”,可以檢視所有内置的和已安裝插件支援的指令:
選擇“Declarative Pipeline directive”,可以檢視聲明式 pipeline 的文法: