持續集成:Jenkins Pipeline語法介紹[轉]

Pipeline在Unix/Linux系統中經常用到,Pipeline將一個命令/程序/進程的輸出發送到另一個命令/程序/進程,以進行進一步處理。比如:cat test.txt | grep test1Jenkins 中的Pipeline借用了Unix/Linux中的 Pipeline思路,實現像流水線一樣來調度Jenkins任務,通過Jenkinsfile來描述整個持續集成流程。

 

 

一個簡單的 Pipeline項目

先來看看如何在Jenkins上創建一個簡單的Pipeline。

新建pipeline任務

新建一個pipeline任務

可以設置構建觸發方式。

接下來開始編寫Pipeline腳本,可選擇Pipline script或者Pipline script from SCM。

  • Pipline script模式是將腳本寫在下面的輸入框中
  • Pipline script from SCM是將Pipeline script放到Git或者SVN上,執行的時候從上面拉下來執行。

Pipeline Script

選擇 Pipeline Script,編寫如下代碼:

pipeline {
    agent any
    stages {
        stage('begin') {
            steps {
                echo 'Hello pipeline'
                }
        }
    }
    post {
        always {
            echo 'say goodbay'
            }
    }
}

 

  • stages:添加執行步驟
  • post:任務執行完成後執行的操作

Pipeline Script from SCM

Pipeline Script除了寫在jenkins界面以外,也可以放入git源碼庫進行管理

在 Jenkins Pipeline任務中選擇 Pipeline script from SCM

添加git源碼地址,在 Script Path中填寫需要運行的Jenkinsfile文件所在的地址

構建

創建完成後保存,點擊Build Now,我們可以看到不同構建階段進度

構建日誌:

Jenkinsfile語法

Jenkinsfile支持兩種語法形式:

  • Scripted pipeline - 腳本式流水線語法,基於 Groovy 語言構建的通用 DSL(Domain-specific language,領域特定語言)
  • Declarative pipeline - 聲明式流水線語法,在v2.5之後引入,支持結構化方式,提供了更豐富的語法特性。

DSL是專注於某個應用領域的計算機語言。和Python、Java等這種通用語言(General-purpose Language, GPL)不同的是,DSL是一種爲了特定領域而設計的開發語言,比如Web 應用使用的HTML、可擴展標記語言XML、SQL語言等。

通常情況下,流水線中聲明式和腳本式語法結合使用。

 

Declarative pipeline

聲明式流水線語法必須包含在一個 pipeline塊內:

pipeline { 
	/* Declarative Pipeline */
}

 

pipeline塊中主要由Sections, Directives, Steps, 或者賦值語句組成。

pipeline {
    agent any
    stages {
        stage('begin') {
            steps {
                echo 'Hello pipeline'
                }
        }
    }
    post {
        always {
            echo 'say goodbay'
        }
    }
}
 

 

Sections

Sections包括agent、stages、steps和post。

agent

agent定義 pipeline執行節點,必須在pipeline 塊的頂層定義。

主要參數:

  • any:可以在任意可用的 agent上執行pipeline
  • none:pipeline將不分配全局agent,每個 stage分配自己的agent
  • label:指定運行節點agent的 Label
  • node:自定義運行節點配置,
    • 指定 label
    • 指定 customWorkspace
  • docker:使用給定的容器執行流水線。
  • dockerfile:使用源碼庫中包含的Dockerfile構建的容器來執行Pipeline。
  • kubernetes:在kubernetes集羣執行Pipeline

上述參數也可以用於stage中。

 

示例腳本:本段配置待定

pipline {
    agent {
        node {
            label "myslave"
            customWorkspace "myWorkspace"
        }
    }
}

 

stages

包含一個或多個 stage, Pipeline的大部分工作在此執行。stages也是必須指定的指令,沒有參數。此外,每個 pipeline塊中必須只有一個 stages。

stage也必須指定,需要定義stage的名字:

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

 

steps

steps位於stage塊中,也是必須設置的指令,無參數。

steps塊中可以包含script塊,可用於存放Scripted Pipeline 腳本:

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

                script {
                    def browsers = ['chrome', 'firefox']
                    for (int i = 0; i < browsers.size(); ++i) {
                        echo "Testing the ${browsers[i]} browser"
                    }
                }
            }
        }
    }
}

 

post

post是在Pipeline或者 stage執行結束後的操作,不是必須出現的指令,可設置以下觸發條件:

  • always:無論 Pipeline或者stage運行完成的狀態如何都會運行
  • changed:只有當前 Pipeline或者stage運行的狀態與先前運行狀態不同時才能運行
  • fixed:只有當前一次構建失敗或者不穩定,而當前 Pipeline或者stage運行成功時運行
  • regression:前一次運行成功,而當前Pipeline或者stage運行狀態爲failure, unstable 或者 aborted時運行
  • aborted:只有當前 Pipeline或者stage處於“aborted”狀態時才能運行。通常是手動終止。
  • failure:當前 Pipeline或者stage處於“failed”狀態時才運行
  • success:當前 Pipeline或者stage具有“success”狀態時才運行
  • unstable:當前 Pipeline或者stage具有“unstable”狀態才運行
  • unsuccessful:當前 Pipeline或者stage不是“success”狀態時運行
  • cleanup:不管Pipeline或stage的狀態如何,在每一個post條件被執行之後運行。

示例腳本:

pipeline {
    agent any
    stages {
        stage('init') {
            steps {
                echo 'Hello World'
            }
        }
    }
    post {
        success {
            echo 'success!'
            sleep 2        
        }

        always {
            echo 'goodbye'
        }
    }
}

 

Directives

Declarative pipeline也包含了各種指令,比如environment,options,parameters,triggers等,指令不是必須出現的指令。

environment

定義 Pipeline或stage運行時的環境變量,位於pipeline塊頂部的 environment 定義的環境變量適用於流水線中的所有步驟,stage 中定義的 environment 只能應用於 stage 中的步驟。

pipeline {
    agent any
    environment { 
        CC = 'clang'
    }
    stages {
        stage('Example') {
            environment { 
                hlw = 'hello world'    
            }
            steps {
                echo hlw
            }
        }
    }
}
 

 

options

options指令允許在Pipeline內部定義 pipeline專有屬性。

 

pipeline可用選項

  • buildDiscarder:保持構建的最大個數,超過最大構建數後會丟棄以前的構建。
  • checkoutToSubdirectory:在工作區的子目錄中執行自動源代碼控制checkout 。
  • disableConcurrentBuilds:禁止並行執行 pipeline任務,可用於防止同時訪問共享資源。
  • disableResume:如果控制器重啓,不允許管道恢復。
  • newContainerPerStage:與docker或dockerfile頂級代理一起使用。指定後,每個階段將運行在同一節點上的新容器實例中,而不是所有階段都運行在同一個容器實例中。
  • overrideIndexTriggers:允許重寫分支索引觸發器的默認處理方法。如果分支索引觸發器在多分支或組織標籤處被禁用,options { overrideIndexTriggers(true) }將僅爲該job啓用。否則,options { overrideIndexTriggers(false) }將只禁用該job的分支索引觸發器。
  • preserveStashes:保留已完成構建的stashes ,以便在stage 重啓時使用。例如: options {preserveStashes()}用於保存最近完成構建的stashes ,或者options {preserveStashes(buildCount: 5)}用於保存最近完成構建的五個堆棧。
  • quietPeriod:爲Pipeline設置靜默期(以秒爲單位),覆蓋全局默認值。例如: options {quietPeriod(30)}
  • skipDefaultCheckout:在agent指令中,默認情況下跳過從源代碼Checkout代碼。例如: options {skipDefaultCheckout()}
  • skipStagesAfterUnstable:一旦構建狀態變爲 “Unstable“ 狀態,就跳過stages。例如: options {skipstagesafterstable ()}
  • retry:失敗後,重試整個 Pipeline的次數例如: options { retry(3) }
  • timeout:爲Pipeline的運行設置一個超時時間,在此之後,Jenkins就中止Pipeline。例如: options {timeout(time: 1, unit: 'HOURS')}
  • timestamps:在所有由Pipeline運行生成的控制檯輸出前加上間。例如: options {timestamp ()}
  • parallelsAlwaysFailFast:將流水線中所有後續並行階段的failfast設置爲true,用於並行執行stage中。例如: options {parallelsAlwaysFailFast()}

 

stage的options指令類似於Pipeline的options指令。然而,stage選項只能包含retry, timeout, 或 timestamps 的步驟,或者與stage相關的聲明性選項,比如skipDefaultCheckout

在stage中,在進入agent或檢查任何 when條件之前調用options指令中的步驟。

stage 可用選項:

  • skipDefaultCheckout
  • timeout:爲當前stage的運行設置一個超時時間
  • retry
  • timestamps

示例腳本:

pipeline {
    agent any
    options {
    	timeout (time: 1, unit: 'HOURS')
    	buildDiscarder(logRotator(numToKeepStr: '2')
    	retry(5)
	}
    stages {
        stage('init') {
            options {
                timeout(time: 30, unit: 'SECONDS') 
            }
            steps {
                echo 'Hello World'
            }
        }
    }
}
 

 

parameters

parameters 指令定義 pipeline的專有參數列表,支持參數類型:

  • string:字符串類型
  • text:文本, 可包括多行
  • booleanParam:布爾參數
  • choice:choice 參數
  • password:密碼參數

示例腳本:

pipeline {
    agent any
    parameters {
        string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '') 
        text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '') 
        booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '')
        choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '')
        password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password')
    }
    stages {
        stage('Example') {
            steps {
                echo "${params.DEPLOY_ENV}"
                echo "${params.PASSWORD}"
            }
        }
    }
}
 

 

triggers

triggers 指令定義了 Pipeline自動化觸發的方式,主要包括3種觸發器:

  • cron:接受一個cron樣式的字符串來定義 Pipeline觸發的間隔週期,例如: triggers { cron('H */4 * * 1-5') }
  • pollSCM:接受一個cron樣式的字符串來定義 Jenkins檢查SCM源碼更新的常規間隔;如果存在新的更改,Pipeline將被重新觸發。例如: triggers { pollSCM('H */4 * * 1-5') }
  • upstream:接受以逗號分隔的job字符串和閾值。當字符串中的任何作業以最小閾值完成時,將重新觸發Pipeline。例如: triggers { upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS) }

更多cron表達式語法介紹可參考 Linux cron定時介紹

示例腳本:

pipeline {
    agent any
    triggers {
        cron('H */4 * * 1-5')
    }
    stages {
        stage('init') {
            steps {
                echo 'Hello World'
            }
        }
    }
}
 

 

stage

前面介紹過,stage指令位於stages塊中,也是必須設置的指令,應至少包含一個。

tools

定義自動安裝和PATH上的工具。如果沒有指定agent,則忽略此參數。

支持如下工具:

  • maven
  • jdk
  • gradle

示例腳本:

pipeline {
    agent any
    tools {
        maven 'apache-maven-3.0.1' 
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}
 

 

其中工具名 apache-maven-3.0.1 必須在jenkins中預先配置:Manage Jenkins -> Global Tool Configuration 。

input

stageinput 指令允許使用 input step提示輸入。 在應用了此 options 後,進入 stageagent 或評估 when 條件前, stage 將暫停。 如果 input 被同意, stage 將會繼續。

可配置選項如下:

  • message:必須指定,是呈現給用戶的信息。
  • id:可選標識符, 默認爲 stage 名稱。
  • ok: "ok"按鈕的可選文本。
  • submitter:以逗號分隔的用戶列表或允許提交 input 的外部組名。默認允許任何用戶。
  • submitterParameter:環境變量的可選名稱。如果存在,用 submitter 名稱設置。
  • parameters:提示提交者提供的一個可選的參數列表。 和前面介紹的parameters 指令定義方法一樣。

示例腳本:

pipeline {
    agent any
    stages {
        stage('Example') {
            input {
                message "Should we continue?"
                ok "Yes, we should."
                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."
            }
        }
    }
}

 

when

when 指令位於stage指令中,允許流水線根據給定的條件決定是否應該執行階段,必須包含至少一個條件。

支持以下嵌套條件:

  • branch:當正在構建的分支與分支模式匹配時執行這個階段, 例如: when { branch 'master' }。注意,只適用於多分支流水線。

  • buildingTag:當構建正在構建標記時執行該階段。例如: when {buildingTag()}

  • environment:當指定的環境變量是給定的值時,執行這個步驟, 例如: when { environment name: 'DEPLOY_TO', value: 'production' }

  • changelog:如果構建的SCM變更日誌包含一個給定的正則表達式模式,則執行該階段,例如: when { changelog '.*^\\[DEPENDENCY\\] .+$' }

  • changeset:如果構建的SCM變更集包含一個或多個匹配給定模式的文件,則執行該階段。例如: when { changeset "**/*.js" }

  • changeRequest:如果當前構建是爲了一個“change request”(比如GitHub的Pull request, GitLab上的Merge request, Gerrit中的change等)時執行這個階段。如果沒有傳遞參數,stage在每次變更請求上運行,例如: when { changeRequest() }

  • environment:當指定的環境變量設置爲給定的值時執行,例如: when { environment name: 'DEPLOY_TO', value: 'production' }

  • equals:當期望值與實際值相等時執行,例如: when { equals expected: 2, actual: currentBuild.number }

  • expression:當指定的Groovy表達式爲true時執行, 例如: when { expression { return params.DEBUG_BUILD } }。注意,當表達式返回字符串時,它們必須轉換爲布爾值,或者返回null來計算爲false。簡單地返回“0”或“false”仍然會被計算爲“true”。

  • tag:如果TAG_NAME變量與給定的模式匹配則執行該階段。例如: when { tag "release-*" }。如果提供了一個空模式,那麼如果存在TAG_NAME變量,則該階段將執行(與 buildingTag() 相同)。

  • not:當嵌套條件是 false 時執行這個階段,它必須包含一個條件,例如: when { not { branch 'master' } }

  • allOf:當所有的嵌套條件都爲 true 時執行,必須包含至少一個條件,例如: when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }

  • anyOf:當至少有一個嵌套條件爲 true 時執行,必須包含至少一個條件,例如: when { anyOf { branch 'master'; branch 'staging' } }

  • triggeredBy:噹噹前構建被給定的參數觸發時執行。例如:

    • when { triggeredBy 'SCMTrigger' }
    • when { triggeredBy 'TimerTrigger' }
    • when { triggeredBy 'BuildUpstreamCause' }
    • when { triggeredBy cause: "UserIdCause", detail: "vlinde" }

在進入 stageagent 前評估 when

  • 默認情況下,如果定義了該stageagent ,則stagewhen 條件將在進入該stageagent之後計算。但是,這可以通過在 when 塊中指定 beforeAgent 選項來更改。如果 beforeAgent 設置爲 true ,則首先計算 when 條件,只有當條件計算爲 true 時才進入 agent

input 指令之前評估 when

  • 默認情況下,如果定義了 stagewhen 條件,則不會在 input 之前求值。但是,這可以通過在 when 塊中指定 beforeInput 選項來更改。如果 beforeInput 設置爲 true , when 條件將首先計算,只有當條件計算爲true時纔會進入input
  • beforeInput true優先級高於beforeAgent true

options 指令之前評估 when

  • 默認情況下,如果stage定義了任何 optionsstagewhen 條件將在進入該stageoptions之後計算。但是,這可以通過在 when 塊中指定 beforeOptions 選項來更改。如果 beforeOptions 設置爲true,則首先計算 when 條件,只有當條件計算爲 true 時纔會進入 options
  • beforeOptions true優先級高於beforeInput truebeforeAgent true

示例腳本:

pipeline {
    agent any
    stages {
        stage('Example Build') {
            steps {
                echo 'Hello World'
            }
        }
        
        stage('Deploy1') {
            when {
                branch 'production1'
            }
            steps {
                echo 'Deploying1'
            }
        }
        
        stage('Deploy2') {
            when {
                allOf {
                    branch 'production2'
                    environment name: 'DEPLOY_TO', value: 'production2'
                }
            }
            steps {
                echo 'Deploying2'
            }
        }
        
        stage('Deploy3') {
            when {
                beforeInput true
                branch 'production3'
            }
            input {
                message "Deploy to production3?"
                id "simple-input"
            }
            steps {
                echo 'Deploying3'
            }
        }
    }
}
 

 

並行執行

聲明式流水線支持多階段並行執行,Parallel 塊中,當其中任何一個階段失敗時,可以通過添加failFast true來強制所有並行階段都中止。也可以在管道定義中添加一個options : options {parallelsAlwaysFailFast() }

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放入矩陣單元中,Matrix可以定義一個多維的 name-value組合矩陣,並將其並行運行。具體使用方法可以參考官方文檔

Scripted pipeline

Scripted pipeline是基於groovy語法定製的一種DSL語言,它的靈活性更高,具有更好的可擴展性。

使用它需要了解一定的groovy語法知識,可參考如下文檔:

請看下面的Scripted pipeline腳本,使用了if/else和try/catch/finally流程控制方法,無論構建狀態是什麼都發送郵件:

node('win_agent') {
    try {
        // 自動化測試 
        stage('Test') {
            TEST_STATU = bat (
                script: '''echo autotest''',
                returnStatus: true
            ) == 0
            
            if ("${TEST_STATU}" == "false") {
                catchError(stageResult: 'FAILURE') {
                    echo "測試未通過"
                    env.LOG = "測試未通過"
                }
            } else {
                echo "測試通過"
                env.LOG = "測試通過"
            }
        }
    } catch (exc) {
    	currentBuild.result = 'FAILURE'
        echo "Something failed, I'm in the catch block."
  	} finally {
    	stage("email") {
            emailext (
                subject: '\'構建通知:${PROJECT_NAME} - Build # ${BUILD_NUMBER} - ${BUILD_STATUS}\'',
                to: "[email protected]", 
                body: '${FILE,path="email.html"}',
                )
        }
  }
}

 

DSL方法步驟

前面介紹Declarative pipeline和Scripted pipeline語法的實例中,使用到了一些方法步驟,比如shechoemailext等,它們是jenkins插件提供的一些方法步驟,下面舉2個例子:

1、bat/sh方法:

STATU = bat (
                script: '''echo 666''',
                returnStatus: true
            ) == 0
echo ${STATU}

 

2、catchError方法:捕獲到異常後,設置當前構建或者階段狀態設置爲FAILURE,並繼續執行Pipeline後面的步驟:

stage('Test') {
    STATU = bat (
                script: '''echo 666''',
                returnStatus: true
            ) == 0
    
    if ("${TEST}" == "false") {
        catchError(stageResult: 'FAILURE') {
            echo "測試未通過"
        }
    } else {
        echo "測試通過"
    }
}

 

也可以用try-catch來實現。

當前jenkins平臺支持的更多步驟可以訪問 http://:/pipeline-syntax/html 查看。

小結

本文介紹了兩種pipeline腳本語法,使用pipeline腳本可以使任務調度更加靈活,特別是對於比較複雜的項目。

另外,這兩種pipeline腳本語法通常會一起使用,爲了讓代碼更加簡潔,建議使用pipeline共享庫,將groovy腳本放到共享庫中,這樣多個pipeline項目就可以共用這些方法,大大減少代碼冗餘。

參考文檔:

  1. https://www.jenkins.io/zh/doc/book/pipeline/
  2. https://www.jenkins.io/doc/book/pipeline/syntax/
  3. https://www.jenkins.io/zh/doc/book/pipeline/syntax
  4. https://www.jenkins.io/blog/2019/12/02/matrix-building-with-scripted-pipeline/
 

絕大部分參考自

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章