玩轉Jenkins Pipeline
Jenkins Pipeline的總體介紹
1.Jenkins Pipeline 的核心概念
Pipeline,簡而言之,就是一套運行於Jenkins上的工作流框架,將原本獨立運行於單個或者多個節點的任務連線起來,實現單個任務難以完成的複雜流程編排與視覺化。
Pipeline是Jenkins2.X的最核心的特性,幫助Jenkins實現從CI到CD與DevOps的轉變
Pipeline是一組外掛,讓Jenkins可以實現持續交付管道的落地和實施。
持續交付管道(CD Pipeline)是將軟體從版本控制階段到交付給使用者或客戶的完整過程的自動化表現。軟體的每一次更改(提交到原始碼管理系統)都要經過一個複雜的過程才能被髮布。
Pipeline提供了一組可擴充套件的工具,通過Pipeline Domain Specific Language(DSL)syntax可以達到Pipeline as Code(Jenkinsfile儲存在專案的原始碼庫)的目的。
Stage:階段,一個Pipeline可以劃分成若干個Stage,每個Stage代表一組操作,例如:“Build”,“Test”,“Deploy”。
注意,Stage是一個邏輯分組的概念,可以跨多個Node
Node:節點,一個Node就是一個Jenkins節點,或者是Master,或者是Agent,是執行Step的具體執行環境。
Step:步驟,Step是最基本的操作單元,小到建立一個目錄,大到構建一個Docker映象,由各類Jenklins Plugin提供,例如:sh ‘make’
Pipeline五大特性
- 程式碼:Pipeline以程式碼的形式實現,通常被檢入原始碼控制,使團隊能夠編輯、審查和迭代其CD流程。
- 可持續性:Jenklins重啟或者中斷後都不會影響Pipeline Job。
- 停頓:Pipeline可以選擇停止並等待任工輸入或批准,然後再繼續Pipeline執行。
- 多功能:Pipeline支援現實世界的複雜CD要求,包括fork/join子程序,迴圈和並行執行工作的能力
- 可擴充套件:Pipeline外掛支援其DSL的自定義擴充套件以及與其他外掛整合的多個選項。
Pipeline和Freestyle的區別
Freestyle:
上游/下游Job排程,如
BuildJob —> TestJob —> DeployJob
在DSL Job裡面排程多個子Job(利用Build Flow Plugin)
Pipeline:
單個Job中完成所有的任務編排
全域性檢視
Multibranch Pipeline根據你的程式碼中Jenlinsfile自動建立Job
Jenlins Pipeline的基礎語法
Pipeline指令碼是由Groovy語言實現(無需專門學習)
支援兩種語法
Declarative 宣告式(在Pipeline plugin 2.5中引入)
Scripted Pipeline 指令碼式
如何建立最基本的PIpeline
直接在Jenkins Web UI 網頁介面中輸入指令碼
通過建立一個jenkinsfile可以檢入專案的原始碼管理庫
通常推薦在Jenkins中直接從原始碼控制(SCM)中載入Jenklinsfile Pipeline
宣告式Pipeline
宣告式Pipeline的基本語法和表示式遵循與Groovy語法相同的規則,但有以下例外:
- 宣告式pipeline必須包含在固定格式pipeline{}快內
- 每個宣告語句必須獨立一行,行尾無需使用分號
- 塊(blocks{})只能包含章節(Sections),指令(Directives),步驟(Steps)或賦值語句
- 屬性引用語句被視為無引數方法呼叫。例:輸入被視為 input()
塊(blocks{})
由大括號括起來的語句,如pipeline{},Section{},parameters{},script{}
章節(Sections)
通常包含一個或多個指令或步驟。如 agent 、post、stages、steps
指令(Directives)
environment、options、parameters、triggers(觸發)、stage、tools、when
步驟(Steps)
Pipeline steps reference
執行指令碼式pipeline:使用script{}
agent
必須存在,agent必須在pipeline塊內的頂層定義,但stage內是否使用使可選的
引數:any/none/label/node/docker/dockerfile
常用選項 label/cuetomWorkspace/reuseNode
示例
agent { label 'my-label' }
agent {
node {
label 'my-label'
customWorkspace '/some/other/path'
}
}
agent {
docker {
image 'nginx:1.12.2'
label 'my-label'
args '-v /tmp:/tmp'
}
}
post 不是必須的,用於pipeline的最外層或者stage{}中
pipeline {
agent any
stages {
stage('Example'){
steps {
echo 'Hello world'
}
}
}
post {
always {
echo 'say goodbay'
}
}
}
stages 必須,包括順序執行的一個或多個stage命令,在pipeline內僅能使用一次,通常位於agent/options後面,例子如上
steps 必須,steps位於stage指令塊內部,包括一個或多個step。僅有一個step的情況下可以忽略關鍵字step及其{},例子如上
environment 不是必須的,environment定義了一組全域性的環境變數鍵值對,存在於pipeline{}或者stage指令內。執行特殊方法credentials()可以獲取jenkins中預定義的憑證明文內容
environment {CC='clang'}
environment {AN_ACCESS_KEY = credentials('my-prefined-secret-text')}
steps {sh 'printenv'}
options 不是必須的 預定義pipeline專有的配置資訊,僅可定義一次
pipeline {
agent any
options{
timeout(time:1,unit: 'HOURS')
}
...
}
parameters 不是必須的 定義引數化構建的引數可選引數 booleanParam,choice,file,text,password,run,string
paramenters {
choice(name:'PerformMavenRelease',choices:'False\nTrue',description:'desc')
password(name:'CredsToUse',description:'Apassword to build with',defaultValue:'')
}
environment {
BUILD_USR_CHOICE="${params.PerformMavenRelease}"
BUILD_USR_CREDS="${params.CredsToUse}"
}
triggers 不是必須的 定義pipeline被自動觸發的方式選項 cron、pollSCM、upstream
triggers {cron('H 4/* 0 0 1-5')}
triggers {pollSCM('H 4/* 0 0 1-5')}
triggers {upstream(upstreamProjects:'job1,job2',threshold:hudson.model.Result.SUCCESS)}
快速建立一個pipeline
新建 選擇pipeline 填寫Job 的名字
填寫相應的pipeline script
pipeline{
agent any
stages {
stage('Build') {
steps{
echo 'This is a build step'
}
}
stage('Test') {
steps{
echo 'This is a test step'
}
}
stage('Deploy') {
steps{
echo 'This is a deploy step'
}
}
}
}
儲存之後,立即構建
常用的輔助工具
- Snipper Generator(程式碼片段生成器,語法檢查器)
- Replay Pipeline(重放pipeline,可以修改script,修改後的不存入config.xml)
- DSL Reference 語法參考手冊
- 全域性變數引用
- Stage View
- BlueOcean(視覺化)
- Pipeline神器:視覺化編輯器
- 命令列Pipeline除錯工具
變數的傳遞
- 自定義變數(區域性)
def username = 'Jenkins'
echo "Hello Mr.${username}"
#注意一定要用雙引號,單引號識別為字串
- 環境變數(區域性)
withEnv(['MYTOOL_HOME=/usr/local/mytool']){
sh '$MYTOOL_HOME/bin/start'
}
- 環境變數(全域性)
environment {CC='clang'}
echo "Compiler is ${env.CC}"
- 引數化構建(全域性)
parameters {string(name:'Jenkins',defaultValue:'Hello',description:'How should I greet the world')}
ehco "${params.Greeting} World!"
判斷
when僅用於stage內部
when的內建條件為:
- when {branch 'master'}
- when {environment name:'DEPLOY_TO',value:'production'}
#當有環境變數 name 為 DEPLOY_TO 值是 production 條件成立
- when {expression {return params.DEBUG_BUILD}}
#表示式返回值為真時
- when {not {branch 'master'}}
- when {allOf {branch 'master'; environment name:'DEBUG_TO',value:'production'}}
#allOf 所有條件都滿足時
- when {anyOf {branch 'master' ; branch 'staging'}}
#anyOf有一個條件滿足時即可
判斷和異常處理
流程控制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
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"
}
}
}
}
}
}
併發
併發需要放在stages中,stages可以巢狀使用
stage下的steps和parallel不能共存,只能二選一
使用了併發的stage不能再有agent/tools
強制所有併發任務退出,加引數 failFast true
人工確認