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愛好部落

Tags: