什么是流水線
jenkins 有 2 種流水線分為聲明式流水線與腳本化流水線,腳本化流水線是 jenkins 舊版本使用的流水線腳本,新版本 Jenkins 推薦使用聲明式流水線。文檔只介紹聲明流水線。
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' ??????} ????} ??} }
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()。
1、Sections
聲明式流水線中的 Sections 不是一個關鍵字或指令,而是包含一個或多個 Agent、Stages、 post、Directives 和 Steps 的代碼區域塊。
1.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 相關的插件,官方文檔:
https://github.com/jenkinsci/kubernetes-plugin/
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 ''' ??} }
1.2 agent 的配置示例
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 ??????????""" ????????} ??????} ????} ??} }
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' ??????} ????} ??} }
1.3 Post
Post 一般用于流水線結束后的進一步處理,比如錯誤通知等。Post 可以針對流水線不同的結果做出不同的處理,就像開發程序的錯誤處理,比如 Python 語言的 try catch。
Post 可以定義在 Pipeline 或 stage 中,目前支持以下條件
always:無論 Pipeline 或 stage 的完成狀態如何,都允許運行該 post 中定義的指令;
changed:只有當前 Pipeline 或 stage 的完成狀態與它之前的運行不同時,才允許在該 post 部分運行該步驟;
fixed:當本次 Pipeline 或 stage 成功,且上一次構建是失敗或不穩定時,允許運行該 post 中定義的指令;
regression:當本次 Pipeline 或 stage 的狀態為失敗、不穩定或終止,且上一次構建的 狀態為成功時,允許運行該 post 中定義的指令;
failure:只有當前 Pipeline 或 stage 的完成狀態為失敗(failure),才允許在 post 部分運行該步驟,通常這時在 Web 界面中顯示為紅色
success:當前狀態為成功(success),執行 post 步驟,通常在 Web 界面中顯示為藍色 或綠色
unstable:當前狀態為不穩定(unstable),執行 post 步驟,通常由于測試失敗或代碼 違規等造成,在 Web 界面中顯示為黃色
aborted:當前狀態為終止(aborted),執行該 post 步驟,通常由于流水線被手動終止觸發,這時在 Web 界面中顯示為灰色;
unsuccessful:當前狀態不是 success 時,執行該 post 步驟;
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!' ????????} ??????} ????} ??} }
1.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、Directives
Directives 可用于一些執行 stage 時的條件判斷或預處理一些數據,和 Sections 一致,Directives 不是一個關鍵字或指令,而是包含了 environment、options、parameters、triggers、stage、tools、 input、when 等配置。
2.1 Environment
Environment 主要用于在流水線中配置的一些環境變量,根據配置的位置決定環境變量的作用域。可以定義在 pipeline 中作為全局變量,也可以配置在 stage 中作為該 stage 的環境變量。該指令支持一個特殊的方法 credentials(),該方法可用于在 Jenkins 環境中通過標識符訪問預定義的憑證。對于類型為 Secret Text 的憑證,credentials()可以將該 Secret 中的文本內容賦值給環境變量。對于類型為標準的賬號密碼型的憑證,指定的環境變量為 username 和 password,并且也會定義兩個額外的環境變量,分別為MYVARNAME_USR和MYVARNAME_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.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" ??????} ????} ??} }
2.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 Two Three ',?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,必須有這個 ??????} ????} ??} }
2.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 執行成功時觸發該流水線
目前支持的狀態有?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' ??????} ????} ??} }
2.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." ??????} ????} ??} }
2.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' ??????} ????} ??} }
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 并將其放置于代碼倉庫中,有以下好處
方便對流水線上的代碼進行復查/迭代
對管道進行審計跟蹤
流水線真正的源代碼能夠被項目的多個成員查看和編輯
1、環境變量
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-{BUILD_NUMBER}, 可以對產物進行命名,比如生產的 jar 包名字、鏡像的 TAG 等;
BUILD_URL:本次構建的完整 URL,比如:http://buildserver/jenkins/job/MyJobName/17/%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" ??????????} ????????} ??????} ????} ??} }
1.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' ??????} ????} ??} }
2、憑證管理
Jenkins 的聲明式流水線語法有一個 credentials()函數,它支持 secret text(加密文本)、username 和 password(用戶名和密碼)以及 secret file(加密文件)等。接下來看一下一些常用的憑證處理方法。
2.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.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:僅包含密碼的附加變量。
2.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 ??????????""" ????????} ??????} ????} ??} }編輯:黃飛
?
評論