Jenkins中使用pipeline
- 2019 年 10 月 4 日
- 筆記
世界上第一個將流水線引入到生產中的,是福特汽車,生產效率大幅提高,大獲成功。軟體中是否也可以流水作業來提高效率呢?
如同工廠的生產線,每個節點只關注自己的任務,然後流向下一個節點。 我們在編排jenkins時,也可以使用這種思想。

Jenkins1.0也能實現自動化構建,但Pipeline能夠將以前project中的配置資訊以steps的方式放在一個腳本里,將原本獨立運行於單個或者多個節點的任務連接起來,實現單個任務難以完成的複雜流程,形成流水式發布,構建步驟視圖化。簡單來說,Pipeline適用的場景更廣泛,能勝任更複雜的發布流程。舉個例子,job構建工作在master節點,自動化測試腳本在slave節點,這時候jenkins1.0就無法同時運行兩個節點,而Pipeline可以。
簡單來說,Pipeline是由一系列任務構成的腳本,這些任務以串列的方式執行。腳本可以用jenkins code(Jenkins插件提供支援)、bash script(Linux)、bat/powershell(Windows)等編寫。
這些腳本可以保存在Jenkins的Web UI或Jenkinsfile中。基於以下三個原因,官方推薦把Pipeline保存在Jenkinsfile中
便於Pipeline腳本的審查/迭代 便於Pipeline腳本的審計跟蹤 Pipeline的唯一真實來源,可以由項目組的多個成員查看和編輯。
Pipeline中的幾個基本概念:
Stage: 階段,一個Pipeline可以劃分為若干個Stage,每個Stage代表一組操作。注意,Stage是一個邏輯分組的概念,可以跨多個Node。 Node: 節點,一個Node就是一個Jenkins節點,或者是Master,或者是slave,是執行Step的具體運行期環境。 Step: 步驟,Step是最基本的操作單元,小到創建一個目錄,大到構建一個Docker鏡像,由各類Jenkins Plugin提供。
使用Pipeline有以下好處:
程式碼:Pipeline以程式碼的形式實現,通常被列入源程式碼控制,使團隊能夠編輯,審查和迭代其傳送流程。
持久:無論是計劃內的還是計劃外的伺服器重啟,Pipeline都是可恢復的。
可停止:Pipeline可接收互動式輸入,以確定是否繼續執行Pipeline。
多功能:Pipeline支援現實世界中複雜的持續交付要求。它支援fork/join、循環執行,並行執行任務的功能。
可擴展:Pipeline插件支援其DSL的自定義擴展 ,以及與其他插件集成的多個選項。
Pipeline的兩種語法 Pipeline可以使用兩種語法編寫,分別是Delcarative Pipeline(聲明式)和Scripted Pipeline(腳本式)。聲明式的語法出現比腳本式語法晚,目的是更容易地編寫Pipeline,前者結構性更強,而後者則更簡潔,但它更像一門程式語言,因此對使用者的編程知識要求更高。
Declarative Pipeline
聲明式Pipeline必須包含在名為pipeline的語句塊中,典型的聲明式Pipeline語法如下:
pipeline { agent any environment { } stages { stage("Build") { steps { sh 'echo Building... } } stage("Test") { steps { sh 'echo Testing...' } } } } 一個合法的Pipeline遵從下面的幾個原則:
頂層語句塊只能是pipeline {} 每一個語句只能寫在一行,沒有分隔符,例如分號「;」 結構塊只能是Sections、Directive、steps或者賦值語句其中之一 所有的屬性引用都被視為沒有參數的方法調用,例如input等同於input()
Sections
Section可以包含一個或多個Directive、steps,常見的Section有
agent
agent指的是一台遠程電腦,或者一個docker服務,通常是一台Jenkins slave伺服器。agent必須在pipeline{}塊裡面的頂層中定義。stage塊中可選,如果pipeline塊中agent的值為none,則每一個stage中都必須設置agent的值。
它的值可以是
any none label node label customWorkspace docker dockerfile post
post 是一個後處理階段,取決於post的位置,如果post定義在pipeline塊中,則所有stage構建完畢,post中的程式碼被執行,如果post定義在某個stage中,則該stage構建完畢之後post被執行。
post中的值有:
always changed fixed regression aborted failure success unstable cleanup
例如:
pipeline { agent any stages { stage('stage 1') { agent any } post { always { echo 'I will always execute after stage 1 finish' } } } post { always { echo 'I will always execute' } } } stages
stages可以包含一個或多個stage,一個stage指一個構建階段 代表stages中的每一個階段,stage中可以嵌套包含stages,嵌套stages中的stage屬於串列(Sequential)任務,即串列stage不能再包含parallel或stages。
pipeline { agent any stages { stage { agent any stages { stage("nested stage") { //此stage中不能繼續包含parallel或stages } } } } } steps steps裡面包含真正的可執行腳本
environment 用於定義環境變數
pipeline { agent any environment { BUILD_VERSION = '1.0' } stages { stage('Get The Evn'){ steps { sh 'pintenv' //or sh 'env' } } } } parameters 定義參數,可定義的參數類型有兩種,分別是字元串和布爾值。parameters中定義的參數可以在steps中通過params對象引用。
pipeline { agent any parameters { string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?') } stages { stage('Example') { steps { echo "Hello ${params.PERSON}" } } } } triggers 觸發器,可定義的觸發器類型如下:
cron 定時執行 pollSCM 定時拉取倉庫中的源碼 upstream 某個上層項目構建完畢觸發
pipeline { agent any triggers { cron('H */4 * * 1-5') } stages { .... } } parallel 定義並行任務,並行任務通常用於多分支Pipeline構建任務中
pipeline { agent any stages { stage('Non-Parallel Stage') { steps { echo 'This stage will be executed first.' } } stage('Parallel Stage') { when { branch 'master' } failFast true parallel { stage('Branch A') { agent { label "for-branch-a" } steps { echo "On Branch A" } } stage('Branch B') { agent { label "for-branch-b" } steps { echo "On Branch B" } } stage('Branch C') { agent { label "for-branch-c" } stages { stage('Nested 1') { steps { echo "In stage Nested 1 within Branch C" } } stage('Nested 2') { steps { echo "In stage Nested 2 within Branch C" } } } } } } } } Scripted Pipeline
Scripted Pipeline對語法的要求比較寬鬆,頂層可以是node,也可以是stage。node可以嵌套stage,stage反過來也可以嵌套node。典型的腳本式Pipeline語法如下:
node { //node可以指定label 例如 node ('label_name') {} stage("Build") { sh 'echo Building...' } stage("Test"){ sh 'echo Testing...' } } 基礎語法 相比起Declarative Pipeline語法中使用塊或指定的形式定義構建過程,Scripted Pipeline則是使用方法(函數)
node 這裡的node對應於Declarative Pipeline的agent,用於指定構建步驟應該在哪個構建伺服器執行。
node('master'){ stage('Build'){ echo 'Building...' } } node可以嵌套stage,也可以被stage嵌套
stage('Build'){ node('linux'){ sh 'echo building in linux' } node('windows'){ bat 'echo building in windows' } } withEnv withEnv方法和environment語句塊對應,用於定義環境變數。
try catch finally 對應於post後處理語句塊
try{ stage('Build'){ echo 'do something' } }catch(err){ }finally{ } properties 可用於添加參數,有Delcarative Pipeline的parameters的作用,也用於建立觸發器
parameters
properties([parameters([string(name: 'username', defaultValue: 'jenkins', description: 'remote user')])]) node { stage('Build'){ echo "${params.username}" } } triggers
node { properties([pipelineTriggers([cron('H */1 * * *')])]) stage('Build') { echo 'Building...' } } parallel 語法和Declarative Pipeline有點不一樣,並行任務之間使用逗號」,「分隔。
stage('Test') { parallel linux: { node('linux') { checkout scm try { unstash 'app' sh 'make check' } finally { junit '**/target/*.xml' } } }, windows: { node('windows') { /* .. snip .. */ } } } OK, 看起來需要記住很多東西,我這裡有兩個方法,減少記憶。 一是用它的語法幫助; 點擊job頁面的Pipline syntax

可以看到各種關鍵字,還可以測試。
二是使用blue ocean blue ocean是一個為Pipeline重新設計的Web UI。jenkins默認沒有安裝這個插件,因此使用之前需要安裝該插件,只需要在插件管理中搜索Blue Ocean,勾選安裝即可,安裝的過程會連同其他依賴插件一起安裝。 安裝完畢重啟,左側面板會自動出現Blue Ocean的菜單. 然後就可以圖形化編輯工作流:

編輯完後會生成Jenkinsfile.
OK, 用一個簡單的實踐,來鞏固這些知識點。 新建一個「流水線」的job。 配置一下自己的jenkins file

運行以後,結果是這樣的。

去blue ocean中看看

如果有不明白的地方,可以去官方文檔看看:https://jenkins.io/zh/doc/tutorials/create-a-pipeline-in-blue-ocean/
如果掌握好了Jenkins pipline, CI/CD 甚至 Devops就更容易上手了。
更多精彩,請關注微信公眾號:python愛好部落