史上最全 Jenkins Pipeline流水線詳解

Linksla發表於2022-11-02

一、什麼是流水線

jenkins 有 2 種流水線分為宣告式流水線與指令碼化流水線,指令碼化流水線是 jenkins 舊版本使用的流水線指令碼,新版本 Jenkins 推薦使用宣告式流水線。文件只介紹宣告流水線。

1.1 宣告式流水線

在宣告式流水線語法中,流水線過程定義在 Pipeline{}中,Pipeline 塊定義了整個流水線中完成的所有工作,比如

引數說明

  • agent any:在任何可用的代理上執行流水線或它的任何階段,也就是執行流水線過程的位置,也可以指定到具體的節點
  • stage:定義流水線的執行過程(相當於一個階段),比如下文所示的 Build、Test、Deploy, 但是這個名字是根據實際情況進行定義的,並非固定的名字
  • steps:執行某階段具體的步驟。
//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
    stages {
      stage( 'Build') {
        steps {
           echo  'Build'
        }
      }
      stage( 'Test') {
        steps {
           echo  'Test'
        }
      }
      stage( 'Deploy') {
        steps {
           echo  'Deploy'
      }
    }
  }
}

1.2 指令碼化流水線

在指令碼化流水線語法中,會有一個或多個 Node(節點)塊在整個流水線中執行核心工作


引數說明:

  • node:在任何可用的代理上執行流水線或它的任何階段,也可以指定到具體的節點
  • stage:和宣告式的含義一致,定義流水線的階段。Stage 塊在指令碼化流水線語法中是可選的,然而在指令碼化流水線中實現 stage 塊,可以清楚地在 Jenkins UI 介面中顯示每個 stage 的任務子集。
//Jenkinsfile (Scripted Pipeline)

node {
  stage( 'Build') {
     echo  'Build'
  }
  stage( 'Test') {
     echo  'Test'
  }
  stage( 'Deploy') {
     echo  'Deploy'
  }
}

二、宣告式流水線

宣告式流水線必須包含在一個 Pipeline 塊中,比如是一個 Pipeline 塊的格式

pipeline {

  /* insert Declarative Pipeline here */
}

在宣告式流水線中有效的基本語句和表示式遵循與 Groovy 的語法同樣的規則,但有以下例外

  • 流水線頂層必須是一個 block,即   pipeline{}
  • 分隔符可以不需要分號,但是每條語句都必須在自己的行上
  • 塊只能由 Sections、Directives、Steps 或 assignment statements 組成
  • 屬性引用語句被當做是無引數的方法呼叫,比如 input 會被當做 input()。

2.1 Sections

宣告式流水線中的 Sections 不是一個關鍵字或指令,而是包含一個或多個 Agent、Stages、 post、Directives 和 Steps 的程式碼區域塊。

1.Agent

Agent 表示整個流水線或特定階段中的步驟和命令執行的位置,該部分必須在 pipeline 塊的頂層被定義,也可以在 stage 中再次定義,但是 stage 級別是可選的。

any

在任何可用的代理上執行流水線,配置語法

pipeline {

  agent any
}

none

表示該 Pipeline 指令碼沒有全域性的 agent 配置。當頂層的 agent 配置為 none 時, 每個 stage 部分都需要包含它自己的 agent。配置語法

pipeline {

  agent none
  stages {
    stage( 'Stage For Build'){
      agent any
    }
  }
}

label

以節點標籤形式選擇某個具體的節點執行 Pipeline 命令,例如:agent { label 'my-defined-label' }。節點需要提前配置標籤。

pipeline {

  agent none
    stages {
      stage( 'Stage For Build'){
        agent { label  'role-master' }
        steps {
           echo  "role-master"
        }
      }
    }
}

node

和 label 配置類似,只不過是可以新增一些額外的配置,比如 customWorkspace(設定預設工作目錄)

pipeline {

  agent none
    stages {
      stage( 'Stage For Build'){
        agent {
          node {
            label  'role-master'
            customWorkspace  "/tmp/zhangzhuo/data"
          }
        }
        steps {
          sh  "echo role-master > 1.txt"
        }
      }
    }
}

dockerfile

使用從原始碼中包含的 Dockerfile 所構建的容器執行流水線或 stage。此時對應的 agent 寫法如下

agent {

   dockerfile {
     filename  'Dockerfile.build'  //dockerfile檔名稱
     dir  'build'                  //執行構建映象的工作目錄
     label  'role-master'          //執行的node節點,標籤選擇
     additionalBuildArgs  '--build-arg version=1.0.2' //構建引數
   }
}

docker

相當於 dockerfile,可以直接使用 docker 欄位指定外部映象即可,可以省去構建的時間。比如使用 maven 映象進行打包,同時可以指定 args

agent{

  docker{
    image  '192.168.10.15/kubernetes/alpine:latest'   //映象地址
    label  'role-master' //執行的節點,標籤選擇
    args  '-v /tmp:/tmp'      //啟動映象的引數
  }
}

kubernetes

需要部署 kubernetes 相關的外掛,官方文件:

Jenkins 也支援使用 Kubernetes 建立 Slave,也就是常說的動態 Slave。配置示例如下

  • cloud: Configure Clouds 的名稱,指定到其中一個 k8s
  • slaveConnectTimeout: 連線超時時間
  • yaml: pod 定義檔案,jnlp 容器的配置必須有配置無需改變,其餘 containerd 根據自己情況指定
  • workspaceVolume:持久化 jenkins 的工作目錄。
    • persistentVolumeClaimWorkspaceVolume:掛載已有 pvc。
workspaceVolume persistentVolumeClaimWorkspaceVolume(claimName: "jenkins-agent", mountPath: "/", readOnly: "false")

  • nfsWorkspaceVolume:掛載 nfs 伺服器目錄
workspaceVolume nfsWorkspaceVolume(serverAddress: 
"192.168.10.254", serverPath: 
"/nfs", readOnly: 
"false")

  • dynamicPVC:動態申請 pvc,任務執行結束後刪除
workspaceVolume dynamicPVC(storageClassName: 
"nfs-client", requestsSize: 
"1Gi", accessModes: 
"ReadWriteMany")

  • emptyDirWorkspaceVolume:臨時目錄,任務執行結束後會隨著 pod 刪除被刪除,主要功能多個任務 container 共享 jenkins 工作目錄。
workspaceVolume emptyDirWorkspaceVolume()

  • hostPathWorkspaceVolume:掛載 node 節點本機目錄,注意掛載本機目錄注意許可權問題,可以先建立設定 777 許可權,否則預設 kubelet 建立的目錄許可權為 755 預設其他使用者沒有寫許可權,執行流水線會報錯。
workspaceVolume hostPathWorkspaceVolume(hostPath: 
"/opt/workspace", readOnly: 
false)

示例


agent 
{

   kubernetes  {
       cloud  'kubernetes'
       slaveConnectTimeout  1200
       workspaceVolume  emptyDirWorkspaceVolume()
       yaml  '''
kind: Pod
metadata:
  name: jenkins-agent
spec:
  containers:
  - args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
    image: '
192.168.10.15 /kubernetes/jnlp:alpine'
     name:  jnlp
     imagePullPolicy:  IfNotPresent
   -  command:
       -  "cat"
     image:  "192.168.10.15/kubernetes/alpine:latest"
     imagePullPolicy:  "IfNotPresent"
     name:  "date"
     tty:  true
   restartPolicy:  Never
'''
  }
}

2.agent 的配置示例

kubernetes 示例

Docker+K8s+Jenkins 主流技術全解影片資料【乾貨免費分享】


pipeline 
{

   agent  {
     kubernetes  {
       cloud  'kubernetes'
       slaveConnectTimeout  1200
       workspaceVolume  emptyDirWorkspaceVolume()
       yaml  '''
kind: Pod
metadata:
  name: jenkins-agent
spec:
  containers:
  - args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
    image: '
192.168.10.15 /kubernetes/jnlp:alpine'
     name:  jnlp
     imagePullPolicy:  IfNotPresent
   -  command:
       -  "cat"
     image:  "192.168.10.15/kubernetes/alpine:latest"
     imagePullPolicy:  "IfNotPresent"
     name:  "date"
     tty:  true
   -  command:
       -  "cat"
     image:  "192.168.10.15/kubernetes/kubectl:apline"
     imagePullPolicy:  "IfNotPresent"
     name:  "kubectl"
     tty:  true
   restartPolicy:  Never
'''
    }
  }
  environment {
    MY_KUBECONFIG = credentials('kubernetes-cluster')

   }
   stages  {
     stage('Data')  {
       steps  {
         container(name:  'date')  {
           sh  """
            date
          """

         }
       }
     }
     stage('echo')  {
       steps  {
         container(name:  'date')  {
           sh  """
            echo 'k8s is pod'
          """

         }
       }
     }
     stage('kubectl')  {
       steps  {
         container(name:  'kubectl')  {
           sh  """
            kubectl get pod -A  --kubeconfig $MY_KUBECONFIG
          """

         }
       }
     }
   }
}

docker 的示例

pipeline {

  agent none
  stages {
    stage( 'Example Build') {
      agent { docker  'maven:3-alpine' }
      steps {
         echo  'Hello, Maven'
        sh  'mvn --version'
      }
    }
    stage( 'Example Test') {
      agent { docker  'openjdk:8-jre' }
      steps {
         echo  'Hello, JDK'
        sh  'java -version'
      }
    }
  }
}

3.Post

  1. Post 一般用於流水線結束後的進一步處理,比如錯誤通知等。Post 可以針對流水線不同的結果做出不同的處理,就像開發程式的錯誤處理,比如 Python 語言的 try catch。
  2. Post 可以定義在 Pipeline 或 stage 中,目前支援以下條件
  3. always:無論 Pipeline 或 stage 的完成狀態如何,都允許執行該 post 中定義的指令;
  4. changed:只有當前 Pipeline 或 stage 的完成狀態與它之前的執行不同時,才允許在該 post 部分執行該步驟;
  5. fixed:當本次 Pipeline 或 stage 成功,且上一次構建是失敗或不穩定時,允許執行該 post 中定義的指令;
  6. regression:當本次 Pipeline 或 stage 的狀態為失敗、不穩定或終止,且上一次構建的 狀態為成功時,允許執行該 post 中定義的指令;
  7. failure:只有當前 Pipeline 或 stage 的完成狀態為失敗(failure),才允許在 post 部分執行該步驟,通常這時在 Web 介面中顯示為紅色
  8. success:當前狀態為成功(success),執行 post 步驟,通常在 Web 介面中顯示為藍色 或綠色
  9. unstable:當前狀態為不穩定(unstable),執行 post 步驟,通常由於測試失敗或程式碼 違規等造成,在 Web 介面中顯示為黃色
  10. aborted:當前狀態為終止(aborted),執行該 post 步驟,通常由於流水線被手動終止觸發,這時在 Web 介面中顯示為灰色;
  11. unsuccessful:當前狀態不是 success 時,執行該 post 步驟;
  12. cleanup:無論 pipeline 或 stage 的完成狀態如何,都允許執行該 post 中定義的指令。和 always 的區別在於,cleanup 會在其它執行之後執行。

示例

一般情況下 post 部分放在流水線的底部,比如本例項,無論 stage 的完成狀態如何,都會輸出一條 I will always say Hello again!資訊

//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  stages {
    stage( 'Example1') {
      steps {
         echo  'Hello World1'
      }
    }
    stage( 'Example2') {
      steps {
         echo  'Hello World2'
      }
    }
  }
  post {
    always {
       echo  'I will always say Hello again!'
    }
  }
}

也可以將 post 寫在 stage,下面示例表示 Example1 執行失敗執行 post。

//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  stages {
    stage( 'Example1') {
      steps {
        sh  'ip a'
      }
      post {
        failure {
           echo  'I will always say Hello again!'
        }
      }
    }
  }
}

4.sepes

Steps 部分在給定的 stage 指令中執行的一個或多個步驟,比如在 steps 定義執行一條 shell 命令

//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  stages {
    stage( 'Example') {
      steps {
         echo  'Hello World'
      }
    }
  }
}

或者是使用 sh 欄位執行多條指令

//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  stages {
    stage( 'Example') {
      steps {
        sh  """
           echo 'Hello World1'
           echo 'Hello World2'
        """

      }
    }
  }
}

2.2 Directives

Directives 可用於一些執行 stage 時的條件判斷或預處理一些資料,和 Sections 一致,Directives 不是一個關鍵字或指令,而是包含了 environment、options、parameters、triggers、stage、tools、 input、when 等配置。

1.Environment

Environment 主要用於在流水線中配置的一些環境變數,根據配置的位置決定環境變數的作用域。可以定義在 pipeline 中作為全域性變數,也可以配置在 stage 中作為該 stage 的環境變數。該指令支援一個特殊的方法   credentials(),該方法可用於在 Jenkins 環境中透過識別符號訪問預定義的憑證。對於型別為 Secret Text 的憑證, credentials()可以將該 Secret 中的文字內容賦值給環境變數。對於型別為標準的賬號密碼型的憑證,指定的環境變數為 username 和 password,並且也會定義兩個額外的環境變數,分別為 MYVARNAME_USRMYVARNAME_PSW

基本變數使用

//示例

pipeline {
  agent any
  environment {   //全域性變數,會在所有stage中生效
    NAME=  'zhangzhuo'
  }
  stages {
    stage( 'env1') {
      environment { //定義在stage中的變數只會在當前stage生效,其他的stage不會生效
        HARBOR =  'https://192.168.10.15'
      }
      steps {
        sh  "env"
      }
    }
    stage( 'env2') {
      steps {
        sh  "env"
      }
    }
  }
}

使用變數引用 secret 的憑證

//這裡使用k8s的kubeconfig檔案示例

pipeline {
  agent any
  environment {
    KUBECONFIG = credentials( 'kubernetes-cluster')
  }
  stages {
    stage( 'env') {
      steps {
        sh  "env"  //預設情況下輸出的變數內容會被加密
      }
    }
  }
}

使用變數引用型別為標準的賬號密碼型的憑證

這裡使用 HARBOR 變數進行演示,預設情況下賬號密碼型的憑證會自動建立 3 個變數

  • HARBOR_USR:會把憑證中 username 值賦值給這個變數
  • HARBOR_PSW:會把憑證中 password 值賦值給這個變數
  • HARBOR:預設情況下賦值的值為 usernamme:password
//這裡使用k8s的kubeconfig檔案示例

pipeline {
  agent any
  environment {
    HARBOR = credentials( 'harbor-account')
  }
  stages {
    stage( 'env') {
      steps {
        sh  "env"
      }
    }
  }
}

2.Options

Jenkins 流水線支援很多內建指令,比如 retry 可以對失敗的步驟進行重複執行 n 次,可以根據不同的指令實現不同的效果。比較常用的指令如下:

  • buildDiscarder :保留多少個流水線的構建記錄
  • disableConcurrentBuilds:禁止流水線並行執行,防止並行流水線同時訪問共享資源導致流水線失敗。
  • disableResume :如果控制器重啟,禁止流水線自動恢復。
  • newContainerPerStage:agent 為 docker 或 dockerfile 時,每個階段將在同一個節點的新容器中執行,而不是所有的階段都在同一個容器中執行。
  • quietPeriod:流水線靜默期,也就是觸發流水線後等待一會在執行。
  • retry:流水線失敗後重試次數。
  • timeout:設定流水線的超時時間,超過流水線時間,job 會自動終止。如果不加 unit 引數預設為 1 分。
  • timestamps:為控制檯輸出時間戳。

定義在 pipeline 中

pipeline {

  agent any
  options {
    timeout(time: 1, unit:  'HOURS')  //超時時間1小時,如果不加unit引數預設為1分
    timestamps()                     //所有輸出每行都會列印時間戳
    buildDiscarder(logRotator(numToKeepStr:  '3')) //保留三個歷史構建版本
    quietPeriod(10)  //注意手動觸發的構建不生效
    retry(3)    //流水線失敗後重試次數
  }
  stages {
    stage( 'env1') {
      steps {
        sh  "env"
        sleep 2
      }
    }
    stage( 'env2') {
      steps {
        sh  "env"
      }
    }
  }
}

定義在 stage 中

Option 除了寫在 Pipeline 頂層,還可以寫在 stage 中,但是寫在 stage 中的 option 僅支援 retry、 timeout、timestamps,或者是和 stage 相關的宣告式選項,比如 skipDefaultCheckout。處於 stage 級別的 options 寫法如下

pipeline {

  agent any
  stages {
    stage( 'env1') {
      options {   //定義在這裡這對這個stage生效
        timeout(time: 2, unit:  'SECONDS') //超時時間2秒
        timestamps()                     //所有輸出每行都會列印時間戳
        retry(3)    //流水線失敗後重試次數
      }
      steps {
        sh  "env && sleep 2"
      }
    }
    stage( 'env2') {
      steps {
        sh  "env"
      }
    }
  }
}

3.Parameters

Parameters 提供了一個使用者在觸發流水線時應該提供的引數列表,這些使用者指定引數的值可以透過 params 物件提供給流水線的 step(步驟)。只能定義在 pipeline 頂層。

目前支援的引數型別如下

  • string:字串型別的引數。
  • text:文字型引數,一般用於定義多行文字內容的變數。
  • booleanParam:布林型引數。
  • choice:選擇型引數,一般用於給定幾個可選的值,然後選擇其中一個進行賦值。
  • password:密碼型變數,一般用於定義敏感型變數,在 Jenkins 控制檯會輸出為*。

外掛 Parameters

  • imageTag:映象 tag,需要安裝 Image Tag Parameter 外掛後使用
  • gitParameter:獲取 git 倉庫分支,需要 Git Parameter 外掛後使用

示例

pipeline {

  agent any
  parameters {
    string(name:  'DEPLOY_ENV', defaultValue:   'staging', description:  '1')   //執行構建時需要手動配置字串型別引數,之後賦值給變數
    text(name:   'DEPLOY_TEXT', defaultValue:  'One\nTwo\nThree\n', description:  '2')  //執行構建時需要提供文字引數,之後賦值給變數
    booleanParam(name:  'DEBUG_BUILD',  defaultValue:  true, description:  '3')   //布林型引數
    choice(name:  'CHOICES', choices: [ 'one''two''three'], description:  '4')  //選擇形式列表引數
    password(name:  'PASSWORD', defaultValue:  'SECRET', description:  'A  secret password')  //密碼型別引數,會進行加密
    imageTag(name:  'DOCKER_IMAGE', description:  '', image:  'kubernetes/kubectl', filter:  '.*', defaultTag:  '', registry:  'https://192.168.10.15', credentialId:  'harbor-account', tagOrder:  'NATURAL')   //獲取映象名稱與tag
    gitParameter(branch:  '', branchFilter:  'origin/(.*)', defaultValue:  '', description:  'Branch for build and deploy', name:  'BRANCH', quickFilterEnabled:  false, selectedValue:  'NONE', sortMode:  'NONE',  tagFilter:  '*'type'PT_BRANCH')
  }  //獲取git倉庫分支列表,必須有git引用
  stages {
    stage( 'env1') {
      steps {
        sh  "env"
      }
    }
    stage( 'git') {
      steps {
        git branch:  " $BRANCH", credentialsId:  'gitlab-key', url:  'git@192.168.10.14:root/env.git'   //使用gitParameter,必須有這個
      }
    }
  }
}

4.Triggers

在 Pipeline 中可以用 triggers 實現自動觸發流水線執行任務,可以透過 Webhook、Cron、 pollSCM 和 upstream 等方式觸發流水線。

Cron

定時構建假如某個流水線構建的時間比較長,或者某個流水線需要定期在某個時間段執行構建,可以 使用 cron 配置觸發器,比如週一到週五每隔四個小時執行一次

注意:H 的意思不是 HOURS 的意思,而是 Hash 的縮寫。主要為了解決多個流水線在同一時間同時執行帶來的系統負載壓力。

pipeline {

  agent any
  triggers {
    cron( 'H */4 * * 1-5')   //週一到週五每隔四個小時執行一次
    cron( 'H/12 * * * *')   //每隔12分鐘執行一次
    cron( 'H * * * *')   //每隔1小時執行一次
  }
  stages {
    stage( 'Example') {
      steps {
         echo  'Hello World'
      }
    }
  }
}

Upstream

Upstream 可以根據上游 job 的執行結果決定是否觸發該流水線。比如當 job1 或 job2 執行成功時觸發該流水線

Docker+K8s+Jenkins 主流技術全解影片資料【乾貨免費分享】

目前支援的狀態有 SUCCESS、UNSTABLE、FAILURE、NOT_BUILT、ABORTED 等。

pipeline {

  agent any
  triggers {
    upstream(upstreamProjects:  'env', threshold: hudson.model.Result.SUCCESS)  //當env構建成功時構建這個流水線
  }
  stages {
    stage( 'Example') {
      steps {
         echo  'Hello World'
      }
    }
  }
}

5.Input

Input 欄位可以實現在流水線中進行互動式操作,比如選擇要部署的環境、是否繼續執行某個階段等。

配置 Input 支援以下選項

  • message:必選,需要使用者進行 input 的提示資訊,比如:“是否釋出到生產環境?”;
  • id:可選,input 的識別符號,預設為 stage 的名稱;
  • ok:可選,確認按鈕的顯示資訊,比如:“確定”、“允許”;
  • submitter:可選,允許提交 input 操作的使用者或組的名稱,如果為空,任何登入使用者均可提交 input;
  • parameters:提供一個引數列表供 input 使用。

假如需要配置一個提示訊息為“還繼續麼”、確認按鈕為“繼續”、提供一個 PERSON 的變數的引數,並且只能由登入使用者為 alice 和 bob 提交的 input 流水線

pipeline {

  agent any
  stages {
    stage( 'Example') {
      input {
        message  "還繼續麼?"
        ok  "繼續"
        submitter  "alice,bob"
        parameters {
          string(name:  'PERSON', defaultValue:  'Mr Jenkins', description:  'Who should I say hello to?')
        }
      }
      steps {
         echo  "Hello,  ${PERSON}, nice to meet you."
      }
    }
  }
}

6.when

When 指令允許流水線根據給定的條件決定是否應該執行該 stage,when 指令必須包含至少 一個條件。如果 when 包含多個條件,所有的子條件必須都返回 True,stage 才能執行。

When 也可以結合 not、allOf、anyOf 語法達到更靈活的條件匹配。

目前比較常用的內建條件如下

  • branch:當正在構建的分支與給定的分支匹配時,執行這個 stage。注意,branch 只適用於多分支流水線
  • changelog:匹配提交的 changeLog 決定是否構建,例如: when { changelog '.*^\\[DEPENDENCY\\] .+$' }
  • environment:當指定的環境變數和給定的變數匹配時,執行這個 stage,例如:when { environment name: 'DEPLOY_TO', value: 'production' }
  • equals:當期望值和實際值相同時,執行這個 stage,例如:when { equals expected: 2, actual: currentBuild.number };
  • expression:當指定的 Groovy 表示式評估為 True,執行這個 stage,例如:when { expression { return params.DEBUG_BUILD } };
  • tag:如果 TAG_NAME 的值和給定的條件匹配,執行這個 stage,例如:when { tag "release-" };
  • not:當巢狀條件出現錯誤時,執行這個 stage,必須包含一個條件,例如:when { not { branch 'master' } };
  • allOf:當所有的巢狀條件都正確時,執行這個 stage,必須包含至少一個條件,例如:when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } };
  • anyOf:當至少有一個巢狀條件為 True 時,執行這個 stage,例如:when { anyOf { branch 'master'; branch 'staging' } }。

示例:當分支為 main 時執行 Example Deploy 步驟

pipeline {

  agent any
  stages {
    stage( 'Example Build') {
      steps {
         echo  'Hello World'
      }
    }
    stage( 'Example Deploy') {
      when {
        branch  'main' //多分支流水線,分支為才會執行。
      }
      steps {
         echo  'Deploying'
      }
    }
  }
}

也可以同時配置多個條件,比如分支是 production,而且 DEPLOY_TO 變數的值為 main 時,才執行 Example Deploy

pipeline {

  agent any
  environment {
    DEPLOY_TO =  "main"
  }
  stages {
    stage( 'Example Deploy') {
      when {
        branch  'main'
        environment name:  'DEPLOY_TO', value:  'main'
      }
      steps {
         echo  'Deploying'
      }
    }
  }
}

也可以使用 anyOf 進行匹配其中一個條件即可,比如分支為 main 或 DEPLOY_TO 為 main 或 master 時執行 Deploy

pipeline {

  agent any
  stages {
    stage( 'Example Deploy') {
      when {
        anyOf {
          branch  'main'
          environment name:  'DEPLOY_TO', value:  'main'
          environment name:  'DEPLOY_TO', value:  'master'
        }
      }
      steps {
         echo  'Deploying'
      }
    }
  }
}

也可以使用 expression 進行正則匹配,比如當 BRANCH_NAME 為 main 或 master,並且 DEPLOY_TO 為 master 或 main 時才會執行 Example Deploy

pipeline {

  agent any
  stages {
    stage( 'Example Deploy') {
      when {
        expression { BRANCH_NAME ==~ /(main|master)/ }
        anyOf {
          environment name:  'DEPLOY_TO', value:  'main'
          environment name:  'DEPLOY_TO', value:  'master'
        }
      }
      steps {
         echo  'Deploying'
      }
    }
  }
}

預設情況下,如果定義了某個 stage 的 agent,在進入該 stage 的 agent 後,該 stage 的 when 條件才會被評估,但是可以透過一些選項更改此選項。比如在進入 stage 的 agent 前評估 when, 可以使用 beforeAgent,當 when 為 true 時才進行該 stage

目前支援的前置條件如下

  • beforeAgent:如果 beforeAgent 為 true,則會先評估 when 條件。在 when 條件為 true 時,才會進入該 stage
  • beforeInput:如果 beforeInput 為 true,則會先評估 when 條件。在 when 條件為 true 時,才會進入到 input 階段;
  • beforeOptions:如果 beforeInput 為 true,則會先評估 when 條件。在 when 條件為 true 時,才會進入到 options 階段;

beforeOptions 優先順序大於 beforeInput 大於 beforeAgent

示例

pipeline {

  agent none
  stages {
    stage( 'Example Build') {
      steps {
         echo  'Hello World'
      }
    }
    stage( 'Example Deploy') {
      when {
        beforeAgent  true
        branch  'main'
      }
      steps {
         echo  'Deploying'
      }
    }
  }
}

2.3 Parallel

在宣告式流水線中可以使用 Parallel 欄位,即可很方便的實現併發構建,比如對分支 A、B、 C 進行並行處理

pipeline {

  agent any
  stages {
    stage( 'Non-Parallel Stage') {
      steps {
         echo  'This stage will be executed first.'
      }
    }
    stage( 'Parallel Stage') {
      failFast  true         //表示其中只要有一個分支構建執行失敗,就直接推出不等待其他分支構建
      parallel {
        stage( 'Branch A') {
          steps {
             echo  "On Branch A"
          }
        }
        stage( 'Branch B') {
          steps {
             echo  "On Branch B"
          }
        }
        stage( '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"
              }
            }
          }
        }
      }
    }
  }
}

三、Jenkinsfile 的使用

上面講過流水線支援兩種語法,即宣告式和指令碼式,這兩種語法都支援構建持續交付流水線。並且都可以用來在 Web UI 或 Jenkinsfile 中定義流水線,不過通常將 Jenkinsfile 放置於程式碼倉庫中(當然也可以放在單獨的程式碼倉庫中進行管理)。

建立一個 Jenkinsfile 並將其放置於程式碼倉庫中,有以下好處

  • 方便對流水線上的程式碼進行復查/迭代
  • 對管道進行審計跟蹤
  • 流水線真正的原始碼能夠被專案的多個成員檢視和編輯

3.1 環境變數

1.靜態變數

Jenkins 有許多內建變數可以直接在 Jenkinsfile 中使用,可以透過   JENKINS_URL/pipeline/syntax/globals#env  獲取完整列表。目前比較常用的環境變數如下

  • BUILD_ID:當前構建的 ID,與 Jenkins 版本 1.597+中的 BUILD_NUMBER 完全相同
  • BUILD_NUMBER:當前構建的 ID,和 BUILD_ID 一致
  • BUILD_TAG:用來標識構建的版本號,格式為: jenkins-${JOB_NAME}-${BUILD_NUMBER}, 可以對產物進行命名,比如生產的 jar 包名字、映象的 TAG 等;
  • BUILD_URL:本次構建的完整 URL,比如:

    %EF%BC%9B

  • JOB_NAME:本次構建的專案名稱
  • NODE_NAME:當前構建節點的名稱;
  • JENKINS_URL:Jenkins 完整的 URL,需要在 SystemConfiguration 設定;
  • WORKSPACE:執行構建的工作目錄。

示例如果一個流水線名稱為 print_env,第 2 次構建,各個變數的值。

BUILD_ID:2

BUILD_NUMBER:2
BUILD_TAG:jenkins-print_env-2
BUILD_URL:http://192.168.10.16:8080/job/print_env/2/
JOB_NAME:print_env
NODE_NAME:built-in
JENKINS_URL:http://192.168.10.16:8080/
WORKSPACE:/bitnami/jenkins/home/workspace/print_env

上述變數會儲存在一個 Map 中,可以使用 env.BUILD_ID 或 env.JENKINS_URL 引用某個內建變數

pipeline {

  agent any
  stages {
    stage( 'print env') {
      parallel {
        stage( 'BUILD_ID') {
          steps {
             echo  " $env.BUILD_ID"
          }
        }
        stage( 'BUILD_NUMBER') {
          steps {
             echo  " $env.BUILD_NUMBER"
          }
        }
        stage( 'BUILD_TAG') {
          steps {
             echo  " $env.BUILD_TAG"
          }
        }
      }
    }
  }
}

2.動態變數

動態變數是根據某個指令的結果進行動態賦值,變數的值根據指令的執行結果而不同。如下所示

  • returnStdout:將命令的執行結果賦值給變數,比如下述的命令返回的是 clang,此時 CC 的值為“clang”。
  • returnStatus:將命令的執行狀態賦值給變數,比如下述命令的執行狀態為 1,此時 EXIT_STATUS 的值為 1。
//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  environment {
    // 使用 returnStdout
    CC =  """${sh(
         returnStdout: true,
         script: 'echo -n "
clang "'   //如果使用shell命令的echo賦值變數最好加-n取消換行
         )}"""

    // 使用 returnStatus
    EXIT_STATUS =  """${sh(
         returnStatus: true,
         script: 'exit 1'
         )}"""

  }
  stages {
    stage( 'Example') {
      environment {
        DEBUG_FLAGS =  '-g'
      }
      steps {
        sh  'printenv'
      }
    }
  }
}

3.2 憑證管理

Jenkins 的宣告式流水線語法有一個 credentials()函式,它支援 secret text(加密文字)、username 和 password(使用者名稱和密碼)以及 secret file(加密檔案)等。接下來看一下一些常用的憑證處理方法。

1.加密文字

本例項演示將兩個 Secret 文字憑證分配給單獨的環境變數來訪問 Amazon Web 服務,需要 提前建立這兩個檔案的 credentials(實踐的章節會有演示),Jenkinsfile 檔案的內容如下

//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  environment {
    AWS_ACCESS_KEY_ID = credentials( 'txt1')
    AWS_SECRET_ACCESS_KEY = credentials( 'txt2')
  }
  stages {
    stage( 'Example stage 1') {
      steps {
         echo  " $AWS_ACCESS_KEY_ID"
      }
    }
    stage( 'Example stage 2') {
      steps {
         echo  " $AWS_SECRET_ACCESS_KEY"
      }
    }
  }
}

2.使用者名稱密碼

本示例用來演示 credentials 賬號密碼的使用,比如使用一個公用賬戶訪問 Bitbucket、GitLab、 Harbor 等。假設已經配置完成了使用者名稱密碼形式的 credentials,憑證 ID 為 harbor-account

//Jenkinsfile (Declarative Pipeline)

pipeline {
  agent any
  environment {
    BITBUCKET_COMMON_CREDS = credentials( 'harbor-account')
  }
  stages {
    stage( 'printenv') {
      steps {
        sh  "env"
      }
    }
}

上述的配置會自動生成 3 個環境變數

  • BITBUCKET_COMMON_CREDS:包含一個以冒號分隔的使用者名稱和密碼,格式為 username:password
  • BITBUCKET_COMMON_CREDS_USR:僅包含使用者名稱的附加變數
  • BITBUCKET_COMMON_CREDS_PSW:僅包含密碼的附加變數。

3.加密檔案

需要加密儲存的檔案,也可以使用 credential,比如連結到 Kubernetes 叢集的 kubeconfig 檔案等。

假如已經配置好了一個 kubeconfig 檔案,此時可以在 Pipeline 中引用該檔案


//Jenkinsfile 
(Declarative 
Pipeline)

pipeline  {
   agent  {
     kubernetes  {
       cloud  'kubernetes'
       slaveConnectTimeout  1200
       workspaceVolume  emptyDirWorkspaceVolume()
       yaml  '''
kind: Pod
metadata:
  name: jenkins-agent
spec:
  containers:
  - args: [\'$(JENKINS_SECRET)\', \'$(JENKINS_NAME)\']
    image: '
192.168.10.15 /kubernetes/jnlp:alpine'
     name:  jnlp
     imagePullPolicy:  IfNotPresent
   -  command:
       -  "cat"
     image:  "192.168.10.15/kubernetes/kubectl:apline"
     imagePullPolicy:  "IfNotPresent"
     name:  "kubectl"
     tty:  true
   restartPolicy:  Never
'''
    }
  }
  environment {
    MY_KUBECONFIG = credentials('kubernetes-cluster')

   }
   stages  {
     stage('kubectl')  {
       steps  {
         container(name:  'kubectl')  {
           sh  """
            kubectl get pod -A  --kubeconfig $MY_KUBECONFIG
          """

         }
       }
     }
   }
}


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70013542/viewspace-2921566/,如需轉載,請註明出處,否則將追究法律責任。

相關文章