Jenkins Pipeline: pipeline語法詳解


一. 簡介

Pipeline支持兩種語法: Declarative Pipeline(聲明式pipeline,在pipeline2.5中引入,結構化方式)和Scripted Pipeline(腳本式pipeline),兩者都支持建立連續輸送的Pipeline。

相關資料:
https://stackoverflow.com/questions/43484979/jenkins-scripted-pipeline-or-declarative-pipeline
http://jenkins-ci.361315.n4.nabble.com/Declarative-pipelines-vs-scripted-td4891792.html
聲明式Pipeline是后續Open Blue Ocean所支持類型,建議使用聲明式Pipeline的方式進行編寫,從jenkins社區動向看,很明顯這種語法結構會是未來的趨勢。

  • 聲明式pipeline可以內嵌腳本式pipeline
  • 聲明式pipeline必須包含在固定格式的pipeline{}內
  • 塊(Block{}): 只能包含章節Sections,指令Directives,步驟Steps或者賦值語句
  • 章節(Sections): 通常包括一個或多個指令或步驟,如agent,post,stages,steps
  • 指令(Directives): environment,options,parameters,triggers,stage,tools,when
  • 步驟(steps): 執行腳本式pipeline,如script{}

二. Declarative Pipeline(聲明式pipeline)

Sections(章節)

agent

Pipeline或特定階段將在Jenkins環境中執行的位置,具體取決於該agent 部分的放置位置;必須在pipeline頂層定義。

參數:
  • any: 在任何可用的agent 上執行Pipeline或stage。例如:agent any
  • none: 當在pipeline塊的頂層使用none時,將不會為整個Pipeline運行分配全局agent ,每個stage部分將需要包含其自己的agent部分。
  • label: 使用有label標簽的agent,例如:agent { label 'my-defined-label' }
  • node: agent { node { label 'labelName' } },等同於 agent { label 'labelName' },但node允許其他選項(如customWorkspace)。
  • docker: 動態供應一個docker節點去執行pipeline或stage,docker還可以接受一個args,直接傳遞給docker run調用。
agent {
    docker {
        image 'maven:3-alpine'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}
  • dockerfile: Dockerfile源存儲庫中包含的容器來構建執行Pipeline或stage。使用此參數,jenkinsfile必須從代碼中加載使用“pipeline from SCM”或者“Multibranch Pipeline”加載

默認是Dockerfile在根目錄: agent { dockerfile true }
如果Dockerfile在另一個目錄,使用dir參數: agent { dockerfile { dir 'someSubDir' } }
可以使用docker build添加參數: agent { dockerfile { additionalBuildArgs '--build-arg foo=bar' } }

pipeline {
    agent { dockerfile true }
    stages {
        stage('Test') {
            steps {
                sh 'node --version'
                sh 'svn --version'
            }
        }
    }
}
常用選項:
  • label: 一個字符串,選擇哪個特定的label標簽,此選項適用於node,docker和dockerfile,並且 node是必需的。
  • customWorkspace: 一個字符串, 自定義工作空間,可以使相對路徑,也可以是絕對路徑。
agent {
    node {
        label 'my-defined-label'
        customWorkspace '/some/other/path'
    }
}
  • reuseNode: 一個布爾值,默認false,如果為true,在同一工作空間中,適用於docker和dockerfile,並且僅在 單個的stage中使用agent才有效。
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'
            }
        }
    }
}
pipeline {
	//使用多個代理,pipeline頂層agent none,每個stage有各自的agent代理
    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'
            }
        }
    }
}

post

定義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 {
	environment {
        CRDE_EAMIL='xxx@163.com'
    }
    post {
        success {
            script {
                //使用wrap([$class: 'BuildUser'])需要安裝user build vars plugin插件
		// JOB_NAME,BUILD_NUMBER,BUILD_USER,env.BUILD_URL是jenkins pipeline內部變量
                wrap([$class: 'BuildUser']) {
                    mail to: "${CRDE_EAMIL}",
                            subject: "pipeline '${JOB_NAME}' (${BUILD_NUMBER}) result",
                            body: "${BUILD_USER}'s pipeline '${JOB_NAME}' (${BUILD_NUMBER}) run success\n請及時前往${env.BUILD_URL}進行查看."
                }
            }
        }
        failure {
            script {
                wrap([$class: 'BuildUser']) {
                    mail to: "${CRDE_EAMIL}",
                            subject: "pipeline '${JOB_NAME}' (${BUILD_NUMBER}) result",
                            body: "${BUILD_USER}'s pipeline '${JOB_NAME}' (${BUILD_NUMBER}) run failure\n請及時前往${env.BUILD_URL}進行查看."
                }
            }
        }
        unstable {
            script {
                wrap([$class: 'BuildUser']) {
                    mail to: "${CRDE_EAMIL}",
                            subject: "pipeline '${JOB_NAME}' (${BUILD_NUMBER}) result",
                            body: "${BUILD_USER}'s pipeline '${JOB_NAME}' (${BUILD_NUMBER}) run unstable\n請及時前往${env.BUILD_URL}進行查看."
                }
            }
        }
    }
}

stages

包含一個或多個stage的序列,Pipeline的大部分工作在此執行。建議stages至少包含至少一個stage指令,用於連接各個交付過程,如構建,測試和部署等。

steps

steps包含一個或多個在stage塊中執行的step序列。

Directives(指令)

environment

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

pipeline {
    agent any
    environment {
        CC = 'clang'
    }
    stages {
        stage('Example') {
            environment {
                AN_ACCESS_KEY = credentials('my-prefined-secret-text')
            }
            steps {
                sh 'printenv'
            }
        }
    }
}

options

允許在Pipeline本身內配置Pipeline專用選項。Pipeline本身提供了許多選項,例如buildDiscarder,但它們也可能由插件提供,例如 timestamps。

常用選項
  • 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 {
        timeout(time: 1, unit: 'HOURS')
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
} 

parameters

parameters指令提供用戶在觸發Pipeline時的參數列表。這些參數值通過該params對象可用於Pipeline步驟。

常用參數

string,choice,booleanParam等

pipeline {
    agent any
	environment {
        CRDE_EAMIL='xxx@163.com'
    }
    parameters {
        string(name: 'PERSON', defaultValue: 'Mr Jenkins', description: 'Who should I say hello to?')
		choice(name: 'server', choices: '192.168.1.1,22,vito,vito111', description: '測試服務器列表選擇(IP,SshPort,Name,Passwd)')
		booleanParam(name: 'isCommit', description: '是否郵件通知部署人員', defaultValue: false)
    }
    stages {
        stage('Example') {
            steps {
                echo "Hello ${params.PERSON}"
		script {
			def split = ${params.server.split(",")}
			serverIP = split[0]
			sshport = split[1]
			username = split[2]
			password = split[3]
			echo "serverIP:${serverIP},sshport:${sshport},username:${username},password:${password}"
		}
            }
        }
		stage('通知人工驗收') {
			steps {
				script {
					wrap([$class: 'BuildUser']) {
                        if(params.isCommit==false){
                            echo "不需要通知部署人員人工驗收"
                        }
                        else{
                            //郵件通知測試人員人工驗收
                            mail to: "${CRDE_EAMIL}",
                                    subject: "pipeline '${JOB_NAME}' (${BUILD_NUMBER})人工驗收通知",
                                    body: "${BUILD_USER}提交的PineLine '${JOB_NAME}' (${BUILD_NUMBER})進入人工驗收環節\\n請及時前往${env.BUILD_URL}進行測試驗收"
                        }
                    }
				}
			}
		}
    }
}

triggers

triggers指令定義了Pipeline自動化觸發的方式。對於與源代碼集成的Pipeline,如GitHub或BitBucket,triggers可能不需要基於webhook的集成也已經存在。目前只有兩個可用的觸發器:cron和pollSCM。

  • cron: 接受一個cron風格的字符串來定義Pipeline觸發的常規間隔,例如: triggers { cron('H 4/* 0 0 1-5') }
  • pollSCM: 接受一個cron風格的字符串來定義Jenkins檢查SCM源更改的常規間隔。如果存在新的更改,則Pipeline將被重新觸發。例如:triggers { pollSCM('H 4/* 0 0 1-5') }
pipeline {
    agent any
    triggers {
        cron('H 4/* 0 0 1-5')
    }
    stages {
        stage('Example') {
            steps {
                echo 'Hello World'
            }
        }
    }
}

stage

stage指令在stages部分中,應包含stop部分,可選agent部分或其他特定於stage的指令。實際上,Pipeline完成的所有實際工作都將包含在一個或多個stage指令中。

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

tools

通過tools可自動安裝工具,並放置環境變量到PATH。如果agent none,這將被忽略。
maven
jdk
gradle

pipeline {
    agent any
    tools {
        //工具名稱必須在Jenkins 管理Jenkins → 全局工具配置中預配置。
        maven 'apache-maven-3.0.1'
    }
    stages {
        stage('Example') {
            steps {
                sh 'mvn --version'
            }
        }
    }
}

when

when指令允許Pipeline根據給定的條件確定是否執行該階段。該when指令必須至少包含一個條件。如果when指令包含多個條件,則所有子條件必須為stage執行返回true。這與子條件嵌套在一個allOf條件中相同。

內置條件
  • 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' } }
pipeline {
    agent any
    stages {
        stage('Example Build') {
            steps {
                echo 'Hello World'
            }
        }
        stage('Example Deploy') {
            when {
                allOf {
                    branch 'production'
                    environment name: 'DEPLOY_TO', value: 'production'
                }
            }
            steps {
                echo 'Deploying'
            }
        }
    }
}

Parallel(並行)

Declarative Pipeline近期新增了對並行嵌套stage的支持,對耗時長,相互不存在依賴的stage可以使用此方式提升運行效率。除了parallel stage,單個parallel里的多個step也可以使用並行的方式運行。

pipeline {
    agent any
    stages {
        stage('Non-Parallel Stage') {
            steps {
                echo 'This stage will be executed first.'
            }
        }
        stage('Parallel Stage') {
            when {
                branch 'master'
            }
            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"
                    }
                }
            }
        }
    }
}

Steps(步驟)

Declarative Pipeline可以使用 Pipeline Steps reference中的所有可用步驟 ,並附加以下僅在Declarative Pipeline中支持的步驟。

script

script步驟需要一個script Pipeline,並在Declarative Pipeline中執行。對於大多數用例,script在Declarative 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"
                    }
                }
            }
        }
    }
}

三. Scripted Pipeline(腳本式pipeline)

流程控制

pipeline腳本同其它腳本語言一樣,從上至下順序執行,它的流程控制取決於Groovy表達式,如if/else條件語句,舉例如下:

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

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

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

Steps

pipeline最核心和基本的部分就是“step”,從根本上來說,steps作為Declarative pipeline和Scripted pipeline語法的最基本的語句構建塊來告訴jenkins應該執行什么操作。

Declarative pipeline和Scripted pipeline的比較

  • 共同點: 兩者都是pipeline代碼的持久實現,都能夠使用pipeline內置的插件或者插件提供的steps,兩者都可以利用共享庫擴展。
  • 區別: 兩者不同之處在於語法和靈活性。Declarative pipeline對用戶來說,語法更嚴格,有固定的組織結構,更容易生成代碼段,使其成為用戶更理想的選擇。但是Scripted pipeline更加靈活,因為Groovy本身只能對結構和語法進行限制,對於更復雜的pipeline來說,用戶可以根據自己的業務進行靈活的實現和擴展。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM