1 流水線(xiàn)
1.1 簡(jiǎn)介
jenkins 有 2 種流水線(xiàn)分為聲明式流水線(xiàn)與腳本化流水線(xiàn),腳本化流水線(xiàn)是 jenkins舊版本使用的流水線(xiàn)腳本,新版本 Jenkins(2.5之后引入) 推薦使用聲明式流水線(xiàn)。
jenkins流水線(xiàn)語(yǔ)法和gradle語(yǔ)法很類(lèi)似,都是基于了groovy的閉包語(yǔ)法
1.2 聲明式流水線(xiàn)簡(jiǎn)介
在聲明式流水線(xiàn)語(yǔ)法中,流水線(xiàn)過(guò)程定義在Pipeline{}中,Pipeline塊定義了整個(gè)流水線(xiàn)中完成的所有工作
參數(shù)說(shuō)明:
-
agent any:在任何可用的代理上執(zhí)行流水線(xiàn)或它的任何階段,也就是執(zhí)行流水線(xiàn)過(guò)程的位置,也可以指定到具體的節(jié)點(diǎn) -
stage:定義流水線(xiàn)的執(zhí)行過(guò)程(相當(dāng)于一個(gè)階段),比如下文所示的Build、Test、Deploy, 但是這個(gè)名字是根據(jù)實(shí)際情況進(jìn)行定義的,并非固定的名字 -
steps:執(zhí)行某階段具體的步驟
示例:
//Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Build'
}
}
stage('Test') {
steps {
echo 'Test'
}
}
stage('Deploy') {
steps {
echo 'Deploy'
}
}
}
}
上面示例中pipeline是一個(gè)閉包,里面的也是閉包,比如:stage('TEST'){...},就是閉包傳參語(yǔ)法,在groovy中,如果方法中最后一個(gè)參數(shù)是閉包,那么閉包可以放在小括號(hào)的外面
1.3 腳本化流水線(xiàn)簡(jiǎn)介
在腳本化流水線(xiàn)語(yǔ)法中,會(huì)有一個(gè)或多個(gè) Node(節(jié)點(diǎn))塊在整個(gè)流水線(xiàn)中執(zhí)行核心工作
參數(shù)說(shuō)明:
-
node:在任何可用的代理上執(zhí)行流水線(xiàn)或它的任何階段,也可以指定到具體的節(jié)點(diǎn) -
stage:和聲明式的含義一致,定義流水線(xiàn)的階段。Stage塊在腳本化流水線(xiàn)語(yǔ)法中是可選的,然而在腳本化流水線(xiàn)中實(shí)現(xiàn)stage塊,可以清楚地在Jenkins UI界面中顯示每個(gè)stage的任務(wù)子集。
示例:
//Jenkinsfile (Scripted Pipeline)
node {
stage('Build') {
echo 'Build'
}
stage('Test') {
echo 'Test'
}
stage('Deploy') {
echo 'Deploy'
}
}
上面示例中node是一個(gè)閉包,里面的stage也是閉包,比如:stage('TEST'){...},就是閉包傳參語(yǔ)法,在groovy中,如果方法中最后一個(gè)參數(shù)是閉包,那么閉包可以放在小括號(hào)的外面
2 聲明式流水線(xiàn)
2.1 規(guī)范
聲明式流水線(xiàn)必須包含在一個(gè) Pipeline 塊中,比如是一個(gè) Pipeline 塊的格式
pipeline {
/* insert Declarative Pipeline here */
}
在聲明式流水線(xiàn)中有效的基本語(yǔ)句和表達(dá)式遵循與Groovy的語(yǔ)法同樣的規(guī)則,但有以下例外:
- 流水線(xiàn)頂層必須是一個(gè)
block,即pipeline{} - 分隔符可以
不需要分號(hào),但是每條語(yǔ)句都必須在自己的行上 - 塊只能由
Sections、Directives、Steps 或 assignment statements組成 - 屬性引用語(yǔ)句被當(dāng)做是無(wú)參數(shù)的方法調(diào)用,比如
input會(huì)被當(dāng)做input()。
2.2 Sections
聲明式流水線(xiàn)中的 Sections 不是一個(gè)關(guān)鍵字或指令,而是包含一個(gè)或多個(gè) Agent、Stages、 post、Directives 和 Steps 的代碼區(qū)域塊。
2.2.1 Agent
Agent表示整個(gè)流水線(xiàn)或特定階段中的步驟和命令執(zhí)行的位置,該部分必須在 pipeline 塊的頂層被定義,也可以在 stage 中再次定義,但是 stage 級(jí)別是可選的
2.2.1.1 any
在任何可用的代理上執(zhí)行流水線(xiàn),配置語(yǔ)法
pipeline {
agent any
}
2.2.1.2 none
表示該 Pipeline 腳本沒(méi)有全局的 agent 配置。當(dāng)頂層的 agent 配置為 none時(shí), 每個(gè) stage 部分都需要包含它自己的 agent。配置語(yǔ)法
pipeline {
agent none
stages {
stage('Stage For Build'){
agent any
}
}
}
2.2.1.3 label
以節(jié)點(diǎn)標(biāo)簽形式選擇某個(gè)具體的節(jié)點(diǎn)執(zhí)行 Pipeline 命令,例如:agent { label 'my-defined-label' }。節(jié)點(diǎn)需要提前配置標(biāo)簽。
pipeline {
agent none
stages {
stage('Stage For Build'){
agent { label 'role-master' }
steps {
echo "role-master"
}
}
}
}
2.2.1.4 node
和 label 配置類(lèi)似,只不過(guò)是可以添加一些額外的配置,比如customWorkspace(設(shè)置默認(rèn)工作目錄)
pipeline {
agent none
stages {
stage('Stage For Build'){
agent {
node {
label 'role-master'
customWorkspace "/tmp/zhangzhuo/data"
}
}
steps {
sh "echo role-master > 1.txt"
}
}
}
}
2.2.1.5 dockerfile
使用從源碼中包含的 Dockerfile 所構(gòu)建的容器執(zhí)行流水線(xiàn)或 stage。此時(shí)對(duì)應(yīng)的 agent寫(xiě)法如下
agent {
dockerfile {
filename 'Dockerfile.build' //dockerfile文件名稱(chēng)
dir 'build' //執(zhí)行構(gòu)建鏡像的工作目錄
label 'role-master' //執(zhí)行的node節(jié)點(diǎn),標(biāo)簽選擇
additionalBuildArgs '--build-arg version=1.0.2' //構(gòu)建參數(shù)
}
}
2.2.1.6 docker
相當(dāng)于 dockerfile,可以直接使用 docker 字段指定外部鏡像即可,可以省去構(gòu)建的時(shí)間。比如使用 maven 鏡像進(jìn)行打包,同時(shí)可以指定 args
agent{
docker{
image '192.168.10.15/kubernetes/alpine:latest' //鏡像地址
label 'role-master' //執(zhí)行的節(jié)點(diǎn),標(biāo)簽選擇
args '-v /tmp:/tmp' //啟動(dòng)鏡像的參數(shù)
}
}
2.2.1.7 kubernetes
需要部署 kubernetes 相關(guān)的插件,官方文檔https://github.com/jenkinsci/kubernetes-plugin/
Jenkins 也支持使用 Kubernetes 創(chuàng)建 Slave,也就是常說(shuō)的動(dòng)態(tài) Slave。配置示例如下
-
cloud: Configure Clouds 的名稱(chēng),指定到其中一個(gè) k8s -
slaveConnectTimeout: 連接超時(shí)時(shí)間 -
yaml: pod 定義文件,jnlp 容器的配置必須有配置無(wú)需改變,其余 containerd 根據(jù)自己情況指定 -
workspaceVolume:持久化 jenkins 的工作目錄。 -
persistentVolumeClaimWorkspaceVolume:掛載已有 pvc。
workspaceVolume persistentVolumeClaimWorkspaceVolume(claimName: "jenkins-agent", mountPath: "/", readOnly: "false") -
nfsWorkspaceVolume:掛載 nfs 服務(wù)器目錄
workspaceVolume nfsWorkspaceVolume(serverAddress: "192.168.10.254", serverPath: "/nfs", readOnly: "false") -
dynamicPVC:動(dòng)態(tài)申請(qǐng) pvc,任務(wù)執(zhí)行結(jié)束后刪除
workspaceVolume dynamicPVC(storageClassName: "nfs-client", requestsSize: "1Gi", accessModes: "ReadWriteMany") -
emptyDirWorkspaceVolume:臨時(shí)目錄,任務(wù)執(zhí)行結(jié)束后會(huì)隨著 pod 刪除被刪除,主要功能多個(gè)任務(wù) container 共享 jenkins 工作目錄。
workspaceVolume emptyDirWorkspaceVolume() -
hostPathWorkspaceVolume:掛載 node 節(jié)點(diǎn)本機(jī)目錄,注意掛載本機(jī)目錄注意權(quán)限問(wèn)題,可以先創(chuàng)建設(shè)置 777 權(quán)限,否則默認(rèn) kubelet 創(chuàng)建的目錄權(quán)限為 755 默認(rèn)其他用戶(hù)沒(méi)有寫(xiě)權(quán)限,執(zhí)行流水線(xiàn)會(huì)報(bào)錯(cuò)。
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.2.2 agent 的配置示例
2.2.2.1 kubernetes 示例
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
"""
}
}
}
}
}
2.2.2.2 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'
}
}
}
}
2.2.3 Post
Post 一般用于流水線(xiàn)結(jié)束后的進(jìn)一步處理,比如錯(cuò)誤通知等。Post 可以針對(duì)流水線(xiàn)不同的結(jié)果做出不同的處理,就像開(kāi)發(fā)程序的錯(cuò)誤處理,比如 Python 語(yǔ)言的 try catch
Post 可以定義在 Pipeline 或 stage 中,目前支持以下條件:
-
always:無(wú)論Pipeline 或 stage的完成狀態(tài)如何,都允許運(yùn)行該post中定義的指令; -
changed:只有當(dāng)前Pipeline 或 stage的完成狀態(tài)與它之前的運(yùn)行不同時(shí),才允許在該post部分運(yùn)行該步驟; -
fixed:當(dāng)本次Pipeline或stage成功,且上一次構(gòu)建是失敗或不穩(wěn)定時(shí),允許運(yùn)行該post中定義的指令; -
regression:當(dāng)本次Pipeline 或 stage的狀態(tài)為失敗、不穩(wěn)定或終止,且上一次構(gòu)建的 狀態(tài)為成功時(shí),允許運(yùn)行該post中定義的指令; -
failure:只有當(dāng)前Pipeline 或 stage的完成狀態(tài)為失?。╢ailure),才允許在post部分運(yùn)行該步驟,通常這時(shí)在 Web 界面中顯示為紅色 -
success:當(dāng)前狀態(tài)為成功(success),執(zhí)行 post 步驟,通常在 Web 界面中顯示為藍(lán)色 或綠色 -
unstable:當(dāng)前狀態(tài)為不穩(wěn)定(unstable),執(zhí)行 post 步驟,通常由于測(cè)試失敗或代碼 違規(guī)等造成,在 Web 界面中顯示為黃色 -
aborted:當(dāng)前狀態(tài)為終止(aborted),執(zhí)行該 post 步驟,通常由于流水線(xiàn)被手動(dòng)終止觸發(fā),這時(shí)在 Web 界面中顯示為灰色; -
unsuccessful:當(dāng)前狀態(tài)不是 success 時(shí),執(zhí)行該 post 步驟; -
cleanup:無(wú)論 pipeline 或 stage 的完成狀態(tài)如何,都允許運(yùn)行該 post 中定義的指令。和always的區(qū)別在于,cleanup會(huì)在其它執(zhí)行之后執(zhí)行。
示例
一般情況下 post 部分放在流水線(xiàn)的底部,比如本實(shí)例,無(wú)論 stage 的完成狀態(tài)如何,都會(huì)輸出一條 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 寫(xiě)在 stage,下面示例表示 Example1 執(zhí)行失敗執(zhí)行 post。
//Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Example1') {
steps {
sh 'ip a'
}
post {
failure {
echo 'I will always say Hello again!'
}
}
}
}
}
2.2.4 sepes
Steps 部分在給定的 stage 指令中執(zhí)行的一個(gè)或多個(gè)步驟,比如在 steps 定義執(zhí)行一條 shell 命令
//Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
或者是使用 sh 字段執(zhí)行多條指令
//Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Example') {
steps {
sh """
echo 'Hello World1'
echo 'Hello World2'
"""
}
}
}
}
2.3 Directives
Directives可用于一些執(zhí)行 stage 時(shí)的條件判斷或預(yù)處理一些數(shù)據(jù),和 Sections 一致,Directives 不是一個(gè)關(guān)鍵字或指令,而是包含了 environment、options、parameters、triggers、stage、tools、 input、when 等配置。
2.3.1 Environment
Environment 主要用于在流水線(xiàn)中配置的一些環(huán)境變量,根據(jù)配置的位置決定環(huán)境變量的作用域??梢远x在 pipeline 中作為全局變量,也可以配置在 stage 中作為該 stage 的環(huán)境變量。
該指令支持一個(gè)特殊的方法 credentials(),該方法可用于在 Jenkins 環(huán)境中通過(guò)標(biāo)識(shí)符訪(fǎng)問(wèn)預(yù)定義的憑證。對(duì)于類(lèi)型為 Secret Text 的憑證,credentials()可以將該 Secret 中的文本內(nèi)容賦值給環(huán)境變量。對(duì)于類(lèi)型為標(biāo)準(zhǔn)的賬號(hào)密碼型的憑證,指定的環(huán)境變量為 username 和 password,并且也會(huì)定義兩個(gè)額外的環(huán)境變量,分別為MYVARNAME_USR和MYVARNAME_PSW。
基本變量使用
//示例
pipeline {
agent any
environment { //全局變量,會(huì)在所有stage中生效
NAME= 'zhangzhuo'
}
stages {
stage('env1') {
environment { //定義在stage中的變量只會(huì)在當(dāng)前stage生效,其他的stage不會(huì)生效
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" //默認(rèn)情況下輸出的變量?jī)?nèi)容會(huì)被加密
}
}
}
}
使用變量引用類(lèi)型為標(biāo)準(zhǔn)的賬號(hào)密碼型的憑證
這里使用 HARBOR 變量進(jìn)行演示,默認(rèn)情況下賬號(hào)密碼型的憑證會(huì)自動(dòng)創(chuàng)建 3 個(gè)變量:
-
HARBOR_USR:會(huì)把憑證中username值賦值給這個(gè)變量 -
HARBOR_PSW:會(huì)把憑證中password值賦值給這個(gè)變量 -
HARBOR:默認(rèn)情況下賦值的值為usernamme:password
//這里使用k8s的kubeconfig文件示例
pipeline {
agent any
environment {
HARBOR = credentials('harbor-account')
}
stages {
stage('env') {
steps {
sh "env"
}
}
}
}
2.3.2 Options
Jenkins 流水線(xiàn)支持很多內(nèi)置指令,比如 retry 可以對(duì)失敗的步驟進(jìn)行重復(fù)執(zhí)行 n 次,可以根據(jù)不同的指令實(shí)現(xiàn)不同的效果。比較常用的指令如下:
-
buildDiscarder:保留多少個(gè)流水線(xiàn)的構(gòu)建記錄 -
disableConcurrentBuilds:禁止流水線(xiàn)并行執(zhí)行,防止并行流水線(xiàn)同時(shí)訪(fǎng)問(wèn)共享資源導(dǎo)致流水線(xiàn)失敗。 -
disableResume:如果控制器重啟,禁止流水線(xiàn)自動(dòng)恢復(fù)。 -
newContainerPerStage:agent 為 docker 或 dockerfile 時(shí),每個(gè)階段將在同一個(gè)節(jié)點(diǎn)的新容器中運(yùn)行,而不是所有的階段都在同一個(gè)容器中運(yùn)行。 -
quietPeriod:流水線(xiàn)靜默期,也就是觸發(fā)流水線(xiàn)后等待一會(huì)在執(zhí)行。 -
retry:流水線(xiàn)失敗后重試次數(shù)。 -
timeout:設(shè)置流水線(xiàn)的超時(shí)時(shí)間,超過(guò)流水線(xiàn)時(shí)間,job 會(huì)自動(dòng)終止。如果不加 unit 參數(shù)默認(rèn)為 1 分。 -
timestamps:為控制臺(tái)輸出時(shí)間戳。
定義在 pipeline 中
pipeline {
agent any
options {
timeout(time: 1, unit: 'HOURS') //超時(shí)時(shí)間1小時(shí),如果不加unit參數(shù)默認(rèn)為1分
timestamps() //所有輸出每行都會(huì)打印時(shí)間戳
buildDiscarder(logRotator(numToKeepStr: '3')) //保留三個(gè)歷史構(gòu)建版本
quietPeriod(10) //注意手動(dòng)觸發(fā)的構(gòu)建不生效
retry(3) //流水線(xiàn)失敗后重試次數(shù)
}
stages {
stage('env1') {
steps {
sh "env"
sleep 2
}
}
stage('env2') {
steps {
sh "env"
}
}
}
}
定義在 stage 中
Option 除了寫(xiě)在 Pipeline 頂層,還可以寫(xiě)在 stage 中,但是寫(xiě)在 stage 中的 option 僅支持 retry、 timeout、timestamps,或者是和 stage 相關(guān)的聲明式選項(xiàng),比如 skipDefaultCheckout。處于 stage 級(jí)別的 options 寫(xiě)法如下
pipeline {
agent any
stages {
stage('env1') {
options { //定義在這里這對(duì)這個(gè)stage生效
timeout(time: 2, unit: 'SECONDS') //超時(shí)時(shí)間2秒
timestamps() //所有輸出每行都會(huì)打印時(shí)間戳
retry(3) //流水線(xiàn)失敗后重試次數(shù)
}
steps {
sh "env && sleep 2"
}
}
stage('env2') {
steps {
sh "env"
}
}
}
}
2.3.3 Parameters
Parameters 提供了一個(gè)用戶(hù)在觸發(fā)流水線(xiàn)時(shí)應(yīng)該提供的參數(shù)列表,這些用戶(hù)指定參數(shù)的值可以通過(guò) params 對(duì)象提供給流水線(xiàn)的 step(步驟)。只能定義在 pipeline 頂層。
目前支持的參數(shù)類(lèi)型如下:
-
string:字符串類(lèi)型的參數(shù)。 -
text:文本型參數(shù),一般用于定義多行文本內(nèi)容的變量。 -
booleanParam:布爾型參數(shù)。 -
choice:選擇型參數(shù),一般用于給定幾個(gè)可選的值,然后選擇其中一個(gè)進(jìn)行賦值。 -
password:密碼型變量,一般用于定義敏感型變量,在 Jenkins 控制臺(tái)會(huì)輸出為*。
插件 Parameters:
-
imageTag:鏡像 tag,需要安裝Image Tag Parameter插件后使用 -
gitParameter:獲取 git 倉(cāng)庫(kù)分支,需要Git Parameter插件后使用
示例
pipeline {
agent any
parameters {
string(name: 'DEPLOY_ENV', defaultValue: 'staging', description: '1') //執(zhí)行構(gòu)建時(shí)需要手動(dòng)配置字符串類(lèi)型參數(shù),之后賦值給變量
text(name: 'DEPLOY_TEXT', defaultValue: 'One\nTwo\nThree\n', description: '2') //執(zhí)行構(gòu)建時(shí)需要提供文本參數(shù),之后賦值給變量
booleanParam(name: 'DEBUG_BUILD', defaultValue: true, description: '3') //布爾型參數(shù)
choice(name: 'CHOICES', choices: ['one', 'two', 'three'], description: '4') //選擇形式列表參數(shù)
password(name: 'PASSWORD', defaultValue: 'SECRET', description: 'A secret password') //密碼類(lèi)型參數(shù),會(huì)進(jìn)行加密
imageTag(name: 'DOCKER_IMAGE', description: '', image: 'kubernetes/kubectl', filter: '.*', defaultTag: '', registry: 'https://192.168.10.15', credentialId: 'harbor-account', tagOrder: 'NATURAL') //獲取鏡像名稱(chēng)與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倉(cāng)庫(kù)分支列表,必須有g(shù)it引用
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,必須有這個(gè)
}
}
}
}
2.3.4 Triggers
在 Pipeline 中可以用 triggers 實(shí)現(xiàn)自動(dòng)觸發(fā)流水線(xiàn)執(zhí)行任務(wù),可以通過(guò) Webhook、Cron、 pollSCM 和 upstream 等方式觸發(fā)流水線(xiàn)。
2.3.4.1 Cron
定時(shí)構(gòu)建假如某個(gè)流水線(xiàn)構(gòu)建的時(shí)間比較長(zhǎng),或者某個(gè)流水線(xiàn)需要定期在某個(gè)時(shí)間段執(zhí)行構(gòu)建,可以 使用 cron 配置觸發(fā)器,比如周一到周五每隔四個(gè)小時(shí)執(zhí)行一次
注意:H 的意思不是 HOURS 的意思,而是 Hash 的縮寫(xiě)。主要為了解決多個(gè)流水線(xiàn)在同一時(shí)間同時(shí)運(yùn)行帶來(lái)的系統(tǒng)負(fù)載壓力。
pipeline {
agent any
triggers {
cron('H */4 * * 1-5') //周一到周五每隔四個(gè)小時(shí)執(zhí)行一次
cron('H/12 * * * *') //每隔12分鐘執(zhí)行一次
cron('H * * * *') //每隔1小時(shí)執(zhí)行一次
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
2.3.4.2 Upstream
Upstream 可以根據(jù)上游 job 的執(zhí)行結(jié)果決定是否觸發(fā)該流水線(xiàn)。比如當(dāng) job1 或 job2 執(zhí)行成功時(shí)觸發(fā)該流水線(xiàn)
目前支持的狀態(tài)有SUCCESS、UNSTABLE、FAILURE、NOT_BUILT、ABORTED等。
pipeline {
agent any
triggers {
upstream(upstreamProjects: 'env', threshold: hudson.model.Result.SUCCESS) //當(dāng)env構(gòu)建成功時(shí)構(gòu)建這個(gè)流水線(xiàn)
}
stages {
stage('Example') {
steps {
echo 'Hello World'
}
}
}
}
2.3.5 Input
Input 字段可以實(shí)現(xiàn)在流水線(xiàn)中進(jìn)行交互式操作,比如選擇要部署的環(huán)境、是否繼續(xù)執(zhí)行某個(gè)階段等。
配置 Input 支持以下選項(xiàng):
-
message:必選,需要用戶(hù)進(jìn)行input的提示信息,比如:“是否發(fā)布到生產(chǎn)環(huán)境?”; -
id:可選,input 的標(biāo)識(shí)符,默認(rèn)為stage的名稱(chēng); -
ok:可選,確認(rèn)按鈕的顯示信息,比如:“確定”、“允許”; -
submitter:可選,允許提交 input 操作的用戶(hù)或組的名稱(chēng),如果為空,任何登錄用戶(hù)均可提交 input; -
parameters:提供一個(gè)參數(shù)列表供 input 使用。
假如需要配置一個(gè)提示消息為“還繼續(xù)么”、確認(rèn)按鈕為“繼續(xù)”、提供一個(gè) PERSON 的變量的參數(shù),并且只能由登錄用戶(hù)為 alice 和 bob 提交的 input 流水線(xiàn)
pipeline {
agent any
stages {
stage('Example') {
input {
message "還繼續(xù)么?"
ok "繼續(xù)"
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."
}
}
}
}
2.3.6 when
When 指令允許流水線(xiàn)根據(jù)給定的條件決定是否應(yīng)該執(zhí)行該 stage,when指令必須包含至少 一個(gè)條件。如果 when 包含多個(gè)條件,所有的子條件必須都返回 True,stage 才能執(zhí)行。
When 也可以結(jié)合 not、allOf、anyOf 語(yǔ)法達(dá)到更靈活的條件匹配。
目前比較常用的內(nèi)置條件如下:
-
branch:當(dāng)正在構(gòu)建的分支與給定的分支匹配時(shí),執(zhí)行這個(gè)stage。注意,branch只適用于多分支流水線(xiàn) -
changelog:匹配提交的changeLog決定是否構(gòu)建,例如:when { changelog '.*^\\[DEPENDENCY\\] .+$' } -
environment:當(dāng)指定的環(huán)境變量和給定的變量匹配時(shí),執(zhí)行這個(gè) stage,例如:when { environment name: 'DEPLOY_TO', value: 'production' } -
equals:當(dāng)期望值和實(shí)際值相同時(shí),執(zhí)行這個(gè) stage,例如:when { equals expected: 2, actual: currentBuild.number }; -
expression:當(dāng)指定的 Groovy 表達(dá)式評(píng)估為 True,執(zhí)行這個(gè) stage,例如:when { expression { return params.DEBUG_BUILD } }; -
tag:如果 TAG_NAME 的值和給定的條件匹配,執(zhí)行這個(gè) stage,例如:when { tag "release-" }; -
not:當(dāng)嵌套條件出現(xiàn)錯(cuò)誤時(shí),執(zhí)行這個(gè) stage,必須包含一個(gè)條件,例如:when { not { branch 'master' } }; -
allOf:當(dāng)所有的嵌套條件都正確時(shí),執(zhí)行這個(gè) stage,必須包含至少一個(gè)條件,例如:when { allOf { branch 'master'; environment name: 'DEPLOY_TO', value: 'production' } }; -
anyOf:當(dāng)至少有一個(gè)嵌套條件為 True 時(shí),執(zhí)行這個(gè) stage,例如:when { anyOf { branch 'master'; branch 'staging' } }
示例:當(dāng)分支為 main 時(shí)執(zhí)行 Example Deploy 步驟
pipeline {
agent any
stages {
stage('Example Build') {
steps {
echo 'Hello World'
}
}
stage('Example Deploy') {
when {
branch 'main' //多分支流水線(xiàn),分支為才會(huì)執(zhí)行。
}
steps {
echo 'Deploying'
}
}
}
}
也可以同時(shí)配置多個(gè)條件,比如分支是 production,而且 DEPLOY_TO 變量的值為 main 時(shí),才執(zhí)行 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 進(jìn)行匹配其中一個(gè)條件即可,比如分支為 main 或 DEPLOY_TO 為 main 或 master 時(shí)執(zhí)行 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 進(jìn)行正則匹配,比如當(dāng) BRANCH_NAME 為 main 或 master,并且 DEPLOY_TO 為 master 或 main 時(shí)才會(huì)執(zhí)行 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'
}
}
}
}
默認(rèn)情況下,如果定義了某個(gè) stage 的 agent,在進(jìn)入該 stage 的 agent 后,該 stage 的 when 條件才會(huì)被評(píng)估,但是可以通過(guò)一些選項(xiàng)更改此選項(xiàng)。比如在進(jìn)入 stage 的 agent 前評(píng)估 when, 可以使用 beforeAgent,當(dāng) when 為 true 時(shí)才進(jìn)行該 stage
目前支持的前置條件如下:
-
beforeAgent:如果beforeAgent為 true,則會(huì)先評(píng)估 when 條件。在 when 條件為 true 時(shí),才會(huì)進(jìn)入該 stage -
beforeInput:如果 beforeInput 為 true,則會(huì)先評(píng)估 when 條件。在 when 條件為 true 時(shí),才會(huì)進(jìn)入到 input 階段; -
beforeOptions:如果 beforeInput 為 true,則會(huì)先評(píng)估 when 條件。在 when 條件為 true 時(shí),才會(huì)進(jìn)入到 options 階段; -
beforeOptions優(yōu)先級(jí)大于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.4 Parallel
在聲明式流水線(xiàn)中可以使用 Parallel 字段,即可很方便的實(shí)現(xiàn)并發(fā)構(gòu)建,比如對(duì)分支 A、B、 C 進(jìn)行并行處理
pipeline {
agent any
stages {
stage('Non-Parallel Stage') {
steps {
echo 'This stage will be executed first.'
}
}
stage('Parallel Stage') {
failFast true //表示其中只要有一個(gè)分支構(gòu)建執(zhí)行失敗,就直接推出不等待其他分支構(gòu)建
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"
}
}
}
}
}
}
}
}
3 Jenkinsfile 的使用
上面講過(guò)流水線(xiàn)支持兩種語(yǔ)法,即聲明式和腳本式,這兩種語(yǔ)法都支持構(gòu)建持續(xù)交付流水線(xiàn)。并且都可以用來(lái)在 Web UI 或 Jenkinsfile 中定義流水線(xiàn),不過(guò)通常將 Jenkinsfile 放置于代碼倉(cāng)庫(kù)中(當(dāng)然也可以放在單獨(dú)的代碼倉(cāng)庫(kù)中進(jìn)行管理)。
創(chuàng)建一個(gè) Jenkinsfile并將其放置于代碼倉(cāng)庫(kù)中,有以下好處:
- 方便對(duì)流水線(xiàn)上的代碼進(jìn)行復(fù)查/迭代
- 對(duì)管道進(jìn)行審計(jì)跟蹤
- 流水線(xiàn)真正的源代碼能夠被項(xiàng)目的多個(gè)成員查看和編輯
3.1 環(huán)境變量
3.1.1 靜態(tài)變量
Jenkins 有許多內(nèi)置變量可以直接在Jenkinsfile 中使用,可以通過(guò)JENKINS_URL/pipeline/syntax/globals#env獲取完整列表。目前比較常用的環(huán)境變量如下:
-
BUILD_ID:當(dāng)前構(gòu)建的 ID,與 Jenkins 版本 1.597+中BUILD_NUMBER完全相同 -
BUILD_NUMBER:當(dāng)前構(gòu)建的 ID,和 BUILD_ID 一致 -
BUILD_TAG:用來(lái)標(biāo)識(shí)構(gòu)建的版本號(hào),格式為:jenkins-{BUILD_NUMBER}, 可以對(duì)產(chǎn)物進(jìn)行命名,比如生產(chǎn)的 jar 包名字、鏡像的 TAG 等; -
BUILD_URL:本次構(gòu)建的完整 URL,比如:http://buildserver/jenkins/job/MyJobName/17/%EF%BC%9B -
JOB_NAME:本次構(gòu)建的項(xiàng)目名稱(chēng) -
NODE_NAME:當(dāng)前構(gòu)建節(jié)點(diǎn)的名稱(chēng); -
JENKINS_URL:Jenkins 完整的 URL,需要在 SystemConfiguration 設(shè)置; -
WORKSPACE:執(zhí)行構(gòu)建的工作目錄。
示例如果一個(gè)流水線(xiàn)名稱(chēng)為print_env,第 2 次構(gòu)建,各個(gè)變量的值。
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
上述變量會(huì)保存在一個(gè) Map 中,可以使用 env.BUILD_ID 或 env.JENKINS_URL 引用某個(gè)內(nèi)置變量
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"
}
}
}
}
}
}
3.1.2 動(dòng)態(tài)變量
動(dòng)態(tài)變量是根據(jù)某個(gè)指令的結(jié)果進(jìn)行動(dòng)態(tài)賦值,變量的值根據(jù)指令的執(zhí)行結(jié)果而不同。如下所示
-
returnStdout:將命令的執(zhí)行結(jié)果賦值給變量,比如下述的命令返回的是 clang,此時(shí) CC 的值為“clang”。 -
returnStatus:將命令的執(zhí)行狀態(tài)賦值給變量,比如下述命令的執(zhí)行狀態(tài)為 1,此時(shí) 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 的聲明式流水線(xiàn)語(yǔ)法有一個(gè) credentials()函數(shù),它支持 secret text(加密文本)、username 和 password(用戶(hù)名和密碼)以及 secret file(加密文件)等。接下來(lái)看一下一些常用的憑證處理方法。
3.2.1 加密文本
本實(shí)例演示將兩個(gè) Secret 文本憑證分配給單獨(dú)的環(huán)境變量來(lái)訪(fǎng)問(wèn) Amazon Web 服務(wù),需要 提前創(chuàng)建這兩個(gè)文件的 credentials(實(shí)踐的章節(jié)會(huì)有演示),Jenkinsfile 文件的內(nèi)容如下
//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"
}
}
}
}
3.2.2 用戶(hù)名密碼
本示例用來(lái)演示 credentials 賬號(hào)密碼的使用,比如使用一個(gè)公用賬戶(hù)訪(fǎng)問(wèn) Bitbucket、GitLab、 Harbor 等。假設(shè)已經(jīng)配置完成了用戶(hù)名密碼形式的 credentials,憑證 ID 為 harbor-account
//Jenkinsfile (Declarative Pipeline)
pipeline {
agent any
environment {
BITBUCKET_COMMON_CREDS = credentials('harbor-account')
}
stages {
stage('printenv') {
steps {
sh "env"
}
}
}
上述的配置會(huì)自動(dòng)生成 3 個(gè)環(huán)境變量:
-
BITBUCKET_COMMON_CREDS:包含一個(gè)以冒號(hào)分隔的用戶(hù)名和密碼,格式為 username:password -
BITBUCKET_COMMON_CREDS_USR:僅包含用戶(hù)名的附加變量 -
BITBUCKET_COMMON_CREDS_PSW:僅包含密碼的附加變量。
3.2.3 加密文件
需要加密保存的文件,也可以使用 credential,比如鏈接到 Kubernetes 集群的 kubeconfig 文件等。
假如已經(jīng)配置好了一個(gè) kubeconfig 文件,此時(shí)可以在 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
"""
}
}
}
}
}
轉(zhuǎn)載于:https://mp.weixin.qq.com/s/xnIpd4bjjt9Nv7bE_hASXQ