【Jenkins系列】-Pipeline語法全集

DevOps在路上發表於2023-04-01

Jenkins為您提供了兩種開發Pipeline的方式:指令碼式和宣告式。

  1. 指令碼式流水線(也稱為“傳統”流水線)基於Groovy作為其特定於域的語言。
  2. 而宣告式流水線提供了簡化且更友好的語法,並帶有用於定義它們的特定語句,而無需學習Groovy。宣告式流水線語法錯誤在指令碼開始時報告。這是一個很好的功能,因為您不會浪費時間,直到某個步驟未能意識到拼寫錯誤或拼寫錯誤。如前所述,流水線可以以宣告式或指令碼式編寫。而且,宣告式方法建立在指令碼式方法的基礎之上,透過新增”script”步驟,可以很容易地進行擴充套件。

宣告式流水線 vs 指令碼式流水線
共同點:

  • 兩者都是pipeline程式碼的持久實現,都能夠使用pipeline內建的外掛或者外掛提供的steps,兩者都可以利用共享庫擴充套件。

區別:

  • 兩者不同之處在於語法和靈活性。
  • Declarative pipeline對使用者來說,語法更嚴格,有固定的組織結構,更容易生成程式碼段,使其成為使用者更理想的選擇。
  • 但是Scripted pipeline更加靈活,因為Groovy本身只能對結構和語法進行限制,對於更復雜的pipeline來說,使用者可以根據自己的業務進行靈活的實現和擴充套件

宣告式流水線

必須使用pipeline語句定義有效的宣告式流水線,幷包括以下必需的部分:

  • agent
  • stages
  • stage
  • steps

另外,還有這些可用的指令:

  • environment (在流水線或階段級別定義)
  • input (階段級別定義)
  • options (在流水線或階段級別定義)
  • parallel
  • parameters
  • post
  • dcript
  • tools
  • triggers
  • when

現在,我們將從所需的指令/部分開始,對列出的每個指令/部分進行描述。

agent

agent agent部分指定整個Pipeline或特定階段將在Jenkins環境中執行的位置,具體取決於該agent 部分的放置位置
需要 必須存在,agent必須在pipeline塊內的頂層定義,但是stage內是否使用為可選
引數
- any:在任何可用的agent 上執行Pipeline或stage。例如:agent any
- none:當在pipeline塊的頂層使用none時,將不會為整個Pipeline執行分配全域性agent ,每個stage部分將需要包含其自己的agent部分。
- label:使用提供的label標籤,在Jenkins環境中可用的代理上執行Pipeline或stage。例如:agent { label 'my-defined-label' }
- node:agent { node { label 'labelName' } },等同於 agent { label 'labelName' },但node允許其他選項(如customWorkspace)
- docker:定義此引數時,執行Pipeline或stage時會動態供應一個docker節點去接受Docker-based的Pipelines。 docker還可以接受一個args,直接傳遞給docker
- dockerfile:使用從Dockerfile源儲存庫中包含的容器來構建執行Pipeline或stage 。
常用引數 這些是可以應用於兩個或多個agent的選項。除非明確定義,否則不需要。
label:一個字串。標記在哪裡執行pipeline或stage。此選項適用於node,docker和dockerfile,並且 node是必需的。
customWorkspace:一個字串。自定義執行的工作空間內。它可以是相對路徑,在這種情況下,自定義工作區將位於節點上的工作空間根目錄下,也可以是絕對路徑。例如:
reuseNode:一個布林值,預設為false。如果為true,則在同一工作空間中。此選項適用於docker和dockerfile,並且僅在 individual stage中使用agent才有效。
agent { label 'this k8s-api-label'} 
agent {
    node{
        label ' this is k8sapi-label'
        customWorkspace '/some/other/path'
    }
}
agent {
    docker {
        image 'im-web'
        label 'this is k8sapi-label'
        args '-v /tmp:/tmp'
    }
}

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'
            }
        }
    }
}

pipeline {
    //Execute all the steps defined in this Pipeline within a newly created container of the given name and tag (maven:3-alpine).
    agent { docker 'maven:3-alpine' }
    stages {
        stage('Example Build') {
            steps {
                sh 'mvn -B clean verify'
            }
        }
    }
}

options

options options指令允許在Pipeline本身內配置Pipeline專用選項
需要 否,預定義pipeline專有的配置資訊,僅可定義一次
引數
說明 在流水線級別定義,此指令將對整個流水線的特定選項進行分組。可用的選項有:
- buildDiscarder
- pipeline保持構建的最大個數。例如:options { buildDiscarder(logRotator(numToKeepStr: '1')) }
disableConcurrentBuilds
- 不允許並行執行Pipeline,可用於防止同時訪問共享資源等。例如:options { disableConcurrentBuilds() }
skipDefaultCheckout
- 預設跳過來自原始碼控制的程式碼。例如:options { skipDefaultCheckout() }
skipStagesAfterUnstable
一旦構建狀態進入了“Unstable”狀態,就跳過此stage。例如:options { skipStagesAfterUnstable() }
timeout
- 設定Pipeline執行的超時時間。例如:options { timeout(time: 1, unit: 'HOURS') }
retry
- 失敗後,重試整個Pipeline的次數。例如:options { retry(3) }
timestamps
- 預定義由Pipeline生成的所有控制檯輸出時間。例如:options { timestamps() }
pipeline {
    agent any
    options {
        retry(3)  //將流水線配置為在失敗前重試3次:
    }
    stages {
        echo 'do something'
    }
}

parameters

parameters指令提供使用者在觸發Pipeline時的引數列表。這些引數值透過該params物件可用於Pipeline步驟
目前只支援[booleanParam, choice, credentials, file, text, password, run, string]這幾種引數型別,其他高階引數化型別還需等待社群支援。
image.pngimage.png

parameters
需要 否,定義引數化構建的引數
引數
說明 Only once, inside the pipeline block
pipeline {
    agent any
    parameters {
        string(name: 'user', defaultValue: 'John', description: 'A user that triggers the pipeline')
    }
    stages {
        stage('Trigger pipeline') {
            steps {
                echo "Pipeline triggered by ${params.USER}"
            }
        }
    }
}

pipeline {
    agent any

    options {
        timeout(time:1, unit: 'HOURS')
    }

    parameters {
        choice(name:'PerformMavenRelease',choices:'False\nTrue',description:'desc')
        //   password(name:'CredsToUse',defaultValue:'',description:'A password to build with')
    }

    environment {
        SONAR_SERVER = 'http://172.16.230.171:9000'
        JAVA_HOME='/data/jdk'
    }

    stages {
        stage('sonarserver') {
            steps {
                echo "${SONAR_SERVER}"
            }
        }
        stage('javahome') {
            steps {
                echo "${JAVA_HOME}"
            }
        }
        stage('get parameters') {
            steps {
                echo "${params.PerformMavenRelease}"
            }
        }        
    }
}

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}"
            }
        }
    }
}

stages

stages 包含一個或多個stage的序列,Pipeline的大部分工作在此執行。建議stages至少包含至少一個stage指令,用於連線各個交付過程,如構建,測試和部署等
需要
引數
常用選項 構建後操作的內建判定條件
always, changed, failure, sucess,unstable,aborted
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
    stage('echo') {
        steps {
            echo 'I will ........!'
        }
    }
}

steps

steps
需要 是,steps位於stage指令塊內部,包括一個或者多個step
引數
說明 僅有一個step的情況下可以忽略關鍵字step及其{}
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
    sh 'echo "A one line step"'
    sh '''
    echo "A multiline step"'
    cd /tests/results
    ls -lrt
    '''
}
        }
    }
    stage('echo') {
        steps {  
    bat "mvn clean test -Dsuite=SMOKE_TEST -Denvironment=QA"
    powershell ".\funcional_tests.ps1"
}
    }
}

environment

environment指令指定一系列鍵值對,這些鍵值對將被定義為所有step或stage-specific step的環境變數,具體取決於environment指令在Pipeline中的位置。
該指令支援一種特殊的方法credentials(),可以透過其在Jenkins環境中的識別符號來訪問預定義的憑據。
對於型別為“Secret Text”的憑據,該 credentials()方法將確保指定的環境變數包含Secret Text內容;對於“標準使用者名稱和密碼”型別的憑證,
指定的環境變數將被設定為username:password。

environment
需要 是,environment 定義了一組全域性的環境變數鍵值對
引數
說明 存在於pipeline{} 或者stage指令內,注意特殊方法credentials() ,可以獲取jenkins中預定義的憑證明文內容
//在“pipeline”級別:
pipeline {
    agent any
    
    environment {
        SONAR_SERVER = 'http://172.16.230.171:9000'
    }
    
    stages {
        stage('Example') {
            steps {
                echo "${SONAR_SERVER}"
            }
        }
    }
}

//在”stage”級別:

pipeline {
    agent any
    stages {
        stage ('build') {
            environment {
                OUTPUT_PATH = './outputs/'
            }
            ...
        }
        ...
    }
}

input

“input”指令在階段級別定義,提供提示輸入的功能。該階段將被暫停,直到使用者手動確認為止。
以下配置選項可用於此指令:

  • message:這是必需的選項,其中指定了要顯示給使用者的訊息。
  • id:可選識別符號。預設情況下,使用“階段”名稱。
  • ok:“確定”按鈕的可選文字。
  • submitter:允許提交輸入的使用者或外部組名的可選列表。預設情況下,允許任何使用者。
  • submitterParameter:要使用提交者名稱設定的環境變數的可選名稱(如果存在)。
  • parameters:提交者將提供的可選引數列表。

這是包含此指令的示例流水線:

pipeline {
    agent any
    stages {
        stage ('build') {
            input{
               message "Press Ok to continue"
               submitter "user1,user2"
                parameters {
                   string(name:'username', defaultValue: 'user', description: 'Username of the user pressing Ok')
                }
            }
            steps { 
                echo "User: ${username} said Ok."
            }
        }
    }
}

parallel

Jenkins流水線階段可以在內部巢狀其他階段,這些階段將並行執行。這是透過在指令碼中新增“parallel”指令來完成的。使用示例:

stage('run-parallel-branches') {
    steps {
        parallel(
            a: {
                echo "Tests on Linux"
            },
            b: {
            echo "Tests on Windows"
            }
        )
    }
}

從宣告式流水線1.2版開始,引入了一種新語法,使並行語法的使用更像宣告式的。
使用此新語法重寫的先前指令碼如下所示:

pipeline {
    agent none
    stages {
        stage('Run Tests') {
            parallel {
                stage('Test On Windows') {
                    agent {
                        label "windows"
                    }
                steps {
                    bat "run-tests.bat"
                }
                }
                stage('Test On Linux') {
                    agent {
                        label "linux"
                    }
                    steps {
                        sh "run-tests.sh"
                    }
                }
            }
        }
    }
}

上述的任何一個流水線都將如下所示:

由於兩個指令碼都執行特定的平臺測試,因此它們將在不同的節點上執行測試。如果您的Jenkins伺服器具有足夠的CPU,則還可以透過使用多執行緒將並行用於在同一節點上同時執行階段。
使用並行階段時有一些限制:

  • stage指令可以具有parallel指令或steps指令,但不能同時具有兩者。
  • parallel指令中的一個stage指令不能巢狀另一個parallel指令,僅允許steps。
  • 在內部具有parallel指令的stage指令不能定義“agent”或“tools”指令。

post

post 定義Pipeline或stage執行結束時的操作。post-condition塊支援post部件:always,changed,failure,success,unstable,和aborted。這些塊允許在Pipeline或stage執行結束時執行步驟,具體取決於Pipeline的狀態
需要 否,用於pipeline的最外層或者stage{}中
引數
常用選項 always
執行,無論Pipeline執行的完成狀態如何。
changed
只有當前Pipeline執行的狀態與先前完成的Pipeline的狀態不同時,才能執行。
failure
僅噹噹前Pipeline處於“失敗”狀態時才執行,通常在Web UI中用紅色指示表示。
success
僅噹噹前Pipeline具有“成功”狀態時才執行,通常在具有藍色或綠色指示的Web UI中表示。
unstable
只有當前Pipeline具有“不穩定”狀態,通常由測試失敗,程式碼違例等引起,才能執行。通常在具有黃色指示的Web UI中表示。
aborted
只有當前Pipeline處於“中止”狀態時,才會執行,通常是由於Pipeline被手動中止。通常在具有灰色指示的Web UI中表示。
pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post {
        always {
            echo 'I will always say Hello again!'
        }
    }
}

script

此步驟用於將指令碼化流水線語句新增到宣告式流水線中,從而提供更多功能。此步驟必須包括在“stage”級別。
指令碼塊可以多次用於不同的專案。這些塊使您可以擴充套件Jenkins功能,並可以實現為共享庫。可以在Jenkins共享庫中找到有關此內容的更多資訊。同樣,可以將共享庫匯入並使用到“script”中,從而擴充套件了流水線功能。
接下來,我們將提供示例流水線。第一個只有一個包含一段指令碼化流水線程式碼的塊,而第二個將展示如何匯入和使用共享庫:

pipeline {
    agent any
    stages {
        stage('Sample') {
            steps {
                echo "Scripted block"
                script {

                }
            }
        }
    }
}

tools

可以在流水線級別或階段級別新增“tools”指令。它允許您指定要在指令碼上使用的Maven,JDK或Gradle版本。必須在“全域性工具配置”Jenkins選單上配置這些工具中的任何一個,在撰寫本文時,這三個工具都受支援。
另外,Jenkins將嘗試安裝列出的工具(如果尚未安裝)。透過使用此指令,可以確保安裝了專案所需的特定版本。

pipeline {
    agent any
    tools {
        maven 'apache-maven-3.0.1'  ////工具名稱必須在Jenkins 管理Jenkins → 全域性工具配置中預配置。
    }
    stages {
         echo 'do something'
    }
}

triggers

觸發器允許Jenkins透過使用以下任何一個可用的方式自動觸發流水線:

  • cron:透過使用cron語法,它可以定義何時重新觸發管道。
  • pollSCM:透過使用cron語法,它允許您定義Jenkins何時檢查新的源儲存庫更新。如果檢測到更改,則將重新觸發流水線。(從Jenkins 2.22開始可用)。
  • upstream:將Jenkins任務和閾值條件作為輸入。當列表中的任何任務符合閾值條件時,將觸發流水線。

帶有可用觸發器的示例流水線如下所示:

pipeline {
    agent any
    triggers {
        //Execute weekdays every four hours starting at minute 0
        cron('0 */4 * * 1-5')
    }
    stages {
        ...
    }
}



pipeline {
    agent any
    triggers {
        //Query repository weekdays every four hours starting at minute 0
        pollSCM('0 */4 * * 1-5')
    }
    stages {
        ...
    }
}

pipeline {
    agent any
    triggers {
        //Execute when either job1 or job2 are successful
        upstream(upstreamProjects: 'job1, job2', threshold: hudson.model.Result.SUCCESS)
    }
    stages {
        ...
    }
}

when

when指令允許Pipeline根據給定的條件確定是否執行該階段。該when指令必須至少包含一個條件。如果when指令包含多個條件,則所有子條件必須為stage執行返回true。這與子條件巢狀在一個allOf條件中相同
更復雜的條件結構可使用巢狀條件建:not,allOf或anyOf。巢狀條件可以巢狀到任意深度

| 內建條件
branch:
- 當正在構建的分支與給出的分支模式匹配時執行,例如:when { branch 'master' }。請注意,這僅適用於多分支Pipeline。

environment
- 當指定的環境變數設定為給定值時執行,例如: when { environment name: 'DEPLOY_TO', value: 'production' }

expression
- 當指定的Groovy表示式求值為true時執行,例如: when { expression { return params.DEBUG_BUILD } }

not
- 當巢狀條件為false時執行。必須包含一個條件。例如:when { not { branch 'master' } }

allOf
- 當所有巢狀條件都為真時執行。必須至少包含一個條件。例如:when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }

anyOf
- 當至少一個巢狀條件為真時執行。必須至少包含一個條件。例如:when { anyOf { branch 'master'; branch 'staging' } }

使用方法:
1.when 僅用於stage內部
2. when 的內建條件

  • when {branch 'master'} #當是master的時候,才執行某些事情
  • when {envionment name:'DEPLOY_TO',value:'production'} #當環境變數name 的值是production的時候,才執行某些事情
  • when {expression {return params.DEBUG_BUILD}} #表示式的返回值是真的情況下,才執行
  • when {not {branch 'master'}}#不是master的情況下,執行
  • when {allOf {branch 'master'; environment name: 'DEPLOY_TO',value:'production'}} #當大括號中所有的項都成立,才去做某些事情
  • when {anyOf {branch 'master'; branch 'staging'}} #只要滿足大括號裡面的某一個條件,才去做某些事情

例如,流水線使您可以在具有多個分支的專案上執行任務。這被稱為多分支流水線,其中可以根據分支名稱(例如“master”,“ feature*”,“development”等)採取特定的操作。這是一個示例流水線,它將執行master分支的步驟:

pipeline {
    agent any
    stages {
        stage('Deploy stage') {
            when {
                branch 'master'
            }
            steps {
                echo 'Deploy master to stage'
            }
        }
    }
}

指令碼式流水線

Groovy指令碼不一定適合所有使用者,因此jenkins建立了Declarative pipeline,為編寫Jenkins管道提供了一種更簡單、更有主見的語法。
但是不可否認,由於指令碼化的pipeline是基於groovy的一種DSL語言,所以與宣告式 pipeline相比為jenkins使用者提供了更巨大的靈活性和可擴充套件性。

流程控制if/else條件

pipeline指令碼同其它指令碼語言一樣,從上至下順序執行,它的流程控制取決於Groovy表示式,如if/else條件語句

node {
    stage('Example'){
        if(env.BRANCH_NAME == 'master'){
            echo 'I only execute on the master branch'
        }else {
            echo 'Iexecute elsewhere'
        }
    }
}

異常處理try/catch/finally

pipeline指令碼流程控制的另一種方式是Groovy的異常處理機制。當任何一個步驟因各種原因而出現異常時,都必須在Groovy中使用try/catch/finally語句塊進行處理

node{
    stage('Example'){
        try{
            sh 'exit 1'
        }
        catch (exc) {
            echo 'something failed,I should sound the klaxons!'
            throw
                }
    }
}

迴圈

for迴圈僅存在域指令碼式pipeline中,但是可以透過在宣告式pipeline中呼叫script step來執行

pipeline {
    agent any
    stages {
        stage('Example'){
            steps{
                echo 'Hello world!'
                script {
                    def browsers = ['chrome','firefox']
                    for (int i = 0;i < browers.size();++i){
                        echo "Testing the ${browsers[i]} browser"
                    }
                }
            }
        }
    }
}

於大多數用例,script在Declarative Pipeline中的步驟不是必須的,但它可以提供一個有用的加強。

參考

相關文章