一.簡介
都是在推送代碼后,再切換到Jenkins界面,手動點擊構建。顯然不夠自動化,應該讓每次代碼變動后,就自動進行構建才對。對於pipeline觸發條件,一般從時間觸發和事件觸發。
二.時間觸發
時間觸發是指定義一個時間,時間到了就觸發pipeline執行。在pipeline中,使用trigger指令來定義時間觸發,只能定義在pipeline塊下。支持cron pollSCM upstream三種方式。其它方式可以通過插件來實現。
定時觸發
定時執行就像cronjob,一到時間點就執行。它的使用場景通常是執行一些周期性的job,比如每晚構建。
pipeline {
agent any
triggers {
cron('0 0 * * *')
}
stages {
stage('Nightly build') {
steps {
echo "這是一個耗時的構建,每天凌晨執行"
}
}
}
}
Jenkins tigger cron語法采用UNIX cron語法(有細微差別)。一條cron包含5個字段,使用空格或者Tab分隔,格式為:分,時,日,月,周
- MINUTE:一小時內的分鍾,取值范圍為0~59
- HOUR:一天內的小時,0~23
- DOM:一個月的某幾天,1~31
- MONTH:月份,取值1~12
- DOW:星期幾,取值0~7 0和7代表周日
還可以使用以下特殊字符,一次性指定多個值
- *匹配所有
- M-N,匹配M到N之間的值
- M-N/X or */x 指定到N范圍內,以X值為步長
- A,B,...,Z 使用逗號枚舉多值
在一些大型組織中,會同時存在大量的同一時刻執行的定時任務,比如N個半夜零點 0 0 * * * 執行的任務。這樣會產生負載不均衡。在Jenkins tigger cron語法中使用H字符來解決這一問題,H代表hash。對於沒必要精確到零點0分執行的任務,cron可以這樣寫: H 0 * * *,代表零點0分支59分之前任何一個時間點執行。
需要注意的是,H應用在DOM,一個月的某一天字段時會有不准確的情況,因為10月有31天,而2月卻是28天。
Jenkins trigger cron還設計了一些人性化的別名:@yearly、@annually、@monthly、@weekly、@daily、@midnight和@hourly。
例如@hourly與 H * * * *相同,代表一小時內的任何時間;@midnight實際上代表在半夜12:00到凌晨2:59之前的某個時間。其它別名很少有應用場景。
輪詢代碼倉庫
輪詢代碼倉庫是指定期到代碼倉庫詢問代碼是否有變化,如果有變化就執行。有讀者會問:那多久輪詢一次?筆者的回答是:越頻繁越好。
因為構建的間隔時間越長,在一次構建內就可能會包含多次代碼提交。當構建失敗時,你無法馬上知道那一次代碼提交導致了構建失敗。總之,越不頻繁集成,得到的持續集成的好就越少。
triggers {
pollSCM('H/1 * * * *')
}
這種一般用於特殊情況,比如外網的代碼倉庫無法調用內網的jenkins。則需要用這種方式。
三.事件觸發
事件觸發就是發生了某個事件就觸發pipeline執行,這個事件可以是你能想到的任何事件,比如手動在界面上觸發、其它job主動觸發、HTTP API Webhook觸發等。
由上游任務觸發
當B任務的執行依賴A任務的執行結果時,A就被稱為B的上游任務。
在Jenkins 2.22及以上版本中,trigger指令開始支持upstream類型的觸發條件。upstream的作用就是能讓B pipeline自行決定依賴哪些上游任務。
triggers {
upstream(upstreamProjects: 'job1,job2', threshold: hudson.model.Result.SUCCESS)
}
當upstreamProjects參數接收多個任務時,使用逗號分隔。threshold參數是指上游任務的執行結構是什么值時觸發。hudson.model.Result是一個枚舉,包括以下值:
- ABORTED 任務被手動中止
- FAILURE 構建失敗
- SUCCESS 構建成功
- UNSTABLE 存在一些錯誤,但不至於構建失敗
- NOT_BUILT 在多階段構建時,前面階段的問題導致后面階段無法執行
注意:這種需要手動構建當前任務一次,讓jenkins加載pipeline后,trigger指令才生效
gitlab通知觸發
gitlab通知觸發是指當gitlab發現源代碼有變化時,觸發jenkins執行構建。
由gitlab主動通知進行構建的好處是顯而易見的,這樣很容易就解決了我們之前提到的輪詢代碼倉庫時“多久輪詢一次”的問題,實現每一次代碼變化都對應一次構建。
1.安裝jenkins插件
安裝Generic Webhook Trigger Plugin、git、Gitlab API Plugin、GitLab Plugin插件,注意不是gitlab hook插件(已廢棄)
2.在gitlab創建一個項目,test-a,地址http://1.1.1.1/book/test-a
3.在jenkins上創建pipelien項目,可以同名稱test-a。正常在不使用pipeline進行這個觸發配置的時候,也可以用頁面進行配置,勾選相當於開始接收外界發來的請求。

這里要注意,上面標注的URL是固定輸出的信息,實際項目地址要看WEB欄,這個才是真實地址的

4.生成個人API的Token,用於安全驗證

5.在gitlab項目的設置里,配置鈎子

URL填入如下
http://賬號名:剛才生成的Token@Jenkins的地址/job/test-a/build?job=test-a&token=隨機寫個項目token,這里隨便打
URL直接粘貼了我的
http://zhuhaoran:119db4649f157c0a25f7d2b541d3f4d7da@10.0.12.9:8080/job/test-a/build?job=test-a&token=t8vcxwuza023ehzcftzr5a74vkpto6xr
現在網絡上可能有各種配置,可能老版本適用,但我用的2.220就各種用不了,最后從官網找到這個能用的配置。
為什么這么配置:
gitlab代碼有更新,就會通過上面這個url,將一些請求和相關內容通過post方式傳給Jenkins。Jenkins發現你的test-a項目開啟了這個觸發功能,就會根據pipeline的配置進行相應處理,符合條件后就會觸發執行。
如果只粘貼Jenkins web配置中顯示的地址+Token,會報錯403問題。這是因為如果沒指定賬號密碼,gitlab只能通過匿名用戶去訪問Jenkins去傳參。
但現在大多全局安全配置里,是Role-Based Strategy插件方式管理的

往上都說403要這樣,我感覺是真的蠢,這樣會不安全,而且插件管理和這個只能選擇一個。

6.編寫pipeline,要保存執行一下這個job讓配置生效,具體的參數含義在末尾
pipeline {
agent any
triggers {
gitlab(triggerOnPush: true,
triggerOnMergeRequest: true,
branchFilterType: "All",
secretToken: "t8vcxwuza023ehzcftzr5a74vkpto6xr")
}
stages {
stage('pull') {
steps {
echo '拉取代碼'
}
}
}
}
會發現這里自動勾上了,這是因為pipeline其實就是配置的這個選項,但版本化管理會更好。

7.在gitlab上點擊一下觸發,看是否jenkins job被觸發了

8.然后在gitlab項目中,隨意修改個文件,看是否也能自動觸發
9.參數含義
triggerOnPush: 當Gitlab觸發push事件時,是否執行構建
triggerOnMergeRequest: 當Gitlab觸發mergeRequest事件時,是否執行構建
branchFilterType: 只有符合條件的分支才會觸發構建,必選,否則無法實現觸發。
All: 所有分支
NameBasedFilter: 基於分支名進行過濾,多個分支名使用逗號分隔
includeBranchesSpec: 基於branchFilterType值,輸入期望包括的分支的規則
excludeBranchesSpec: 基於branchFilterType值,輸入期望排除的分支的規則
RegexBasedFilter: 基於正則表達式對分支名進行過濾
sourceBranchRegex: 定義期望的通過正則表達式限制的分支規則
secretToken: 指定這個job_name的token驗證字符
如果只允許master分支push后才觸發,就如下配置,token使用了全局變量,這樣多個項目都可以用一個token,比較方便(內網比較適合)
triggers {
gitlab(triggersOnPush: true,
triggersOnMergeRequest: true,
branchFilterType: "NameBasedFilter",
includeBranchesSpec: "master",
secretToken: "${env.git_token}")
}
用正則匹配,適合對分支號進行規則定義的項目
triggers {
gitlab(triggersOnPush: true,
triggersOnMergeRequest: true,
branchFilterType: "RegexBasedFilter",
sourceBranchRegex: "dev.*",
secretToken: "${env.git_token}")
}
四.通用觸發接口
GWT
前文中,我們講到安裝GitLab插件后,GitLab系統就可以發送Webhook觸發Jenkins項目的執行。那是不是說其他系統想觸發Jenkins項目執行,也需要找一個插件或者開發一個插件來實現呢?
有了Generic Webhook Trigger插件就不需要了,安裝Generic Webhook Trigger插件(下文使用GWT簡稱)后, Jenkins會暴露一個API: <JENKINS URL>/generic-webhook-triggerlinvoke,即由GWT插件來處理此API的請求。
GWT插件接收到JSON或XML的HTTP POST請求后,根據我們配置的規則決定觸發哪個Jenkins項目。下面我們先感受一下,然后再詳細介紹GWT各參數的含義,現在我們創建一個普通的pipeline項目。
代碼如下:
pipeline {
agent any
triggers {
GenericTrigger(
genericVariables:[
[key: 'ref', value: '$.ref']
],
token:'secret',
causeString: 'Triggered on $ref',
printContri butedVariables: true,
printPostContent: true
)
}
stages {
stage('Some step') {
steps {
sh "echo $ref"
sh "printenv"
}
}
}
}
執行一次job后才會生效,然后發起一次HTTP POST請求
curl -X POST -H "Content-Type: application/json" -d '{ "ref": "refs/heads/master" }' -vs http://192.168.23.11:8667/jenkins/generic-webhook-trigger/invoke?token=secret
接着,我們就看到pipeline被觸發執行了。日志如下:
Triggered on refs/heads/master
省略git操作細節部分
Seen branch in repository origin/dev
Seen branch in repository origin/ master
Seen 2 remote branches
Obtained Jenkinsfile from 6b2c6a36ac5fade7448596a5fc67ee33be4bab95
Running in Durability level: MAX_ SURVIVABILITY
Generi cWebhookEnvironmentContributor
Received :
{ "ref": "refs/heads/master" }
Contributing variables:
ref = refs/heads/master
GenericTrigger觸發條件由GWT插件提供。此觸發條件可以說是GWT的所有內容。將GenericTrigger觸發條件分為5部分,這樣更易於理解各參數的作用。
- 從HTTP POST請求中提取參數值
- token,GWT插件用於標識Jenkins項目的唯一性
- 根據請求參數值判斷是否觸發Jenkins項目的執行
- 日志打印控制
- Webhook響應控制
提取參數
一個HTTP POST請求可以從三個維度提取參數,即POST body、URL參數和header。
GWT插件提供了三個參數分別對這三個維度的數據進行提取。
- genericVariables :提取POST body中的參數。
genericVariables:[
[key: 'ref', value: '$.ref'] ,
[key: 'before'
value: ' $.before',
expressionType:' JSONPath
regexpFilter:
defaultValue:
]
]
- value: JSONPath表 達式,或者XPath 表達式,取決於expressionType參數值,用於從POST body中提取值。
- key :從POST body中提取出的值的新變銘,可用於pipeline其他步驟。
- expressionType :可選, value的表達式類型, 默認為JSONPath。當請求為XML內容時,必須指定XPath值。
- defaultValue:可選,當提取不到值,且defaultValue不為空時,則使用defaultValue作為返回值。
- regexpFilter :可選,過濾表達式,對提取出來的值進行過濾。其實就是string.replaceAll ( regexpFilter ,"");。string是從HTTP請求中提取出來的值。
2.genericRequestVariables :從URL參數中提取值。
- key :提取出的值的新變量名,可用於pipeline其他步驟。
- regexpFilter :對提取出的值進行過濾。
3.genericHeaderVariables :從HTTP header中提取值。
genericHeaderVariables的用法與genericRequestVariables-樣,區別是它是從HTTP header中提取值的。
觸發某個具體項目
上面可以看到GenericTrigger方法有一個token參數
GenericTrigger(
token: 'secret',
)
}
token參數的作用是標識一個pipeline在Jenkins中的唯一性(當然,沒有人阻止你讓所有的pipeline使用同-個token)。
為什么需要這個參數呢?這要從GWT插件的原理說起。當Jenkins接收到generic-webhooktriggerlinvoke接口的請求時,會將請求代理給GWT插件處理。GWT插件內部會從Jenkins實例對象中取出所有的參數化Jenkins項目,包括pipeline然后進行遍歷。
如果在參數化項目中GenericTrigger配置的token的值與Webhook請求時的token的值一致,則觸發此參數化項目。如果多個參數化項目的token值一樣,則它們都會被觸發。
pipeline的token可以被設置為Jenkins的項目名
比如:
triggers {
GenericTrigger(
//省略
token: env.JOB_NAME,
//省略
)
}
過濾請求值
上節所說的不完全正確。GWT並不只是根據token值來判斷是否觸發,還可以根據我們提取出的值進行判斷。
示例如下:
GenericTrigger(
genericVariables:[
[key: ' refValue',value: '$.ref']
],
token: env.JOB_NAME,
regexpFilterText:'$refValue',
regexpFilterExpression: 'refs/heads/(master|dev)'
)
- regexpilterText: 需要進行匹配的key。例子中,我們使用從POST body中提取出的refValue變量值。
- regexpFilterExpression :正則表達式。
如果regexpFilterText參數的值符合regexpilterExpression參數的正則表達式,則觸發執行。
控制打印內容
打印日志有助於調試。GWT插件提供了三個參數。
- printPostContent :布爾值, 將Webhook請求信息打印到日志上。
- printContributedVariables:布爾值,將提取后的變量名及變量
- 值打印出來。
- causeString :字符串類型,觸發原因可以直接引用提取后的變量,如causeString : 'Triggered on $msg'。
控制響應
GWT插件最近才加入的一個參數:
silenResponse: 布爾類型,在正常情況下當Webhook請求發布成功后,GWT插件會返回HTTP 200狀態碼和觸發結果給調用方。但是當設置為true時,就只返回HTTP 200狀態碼,不返回觸發結果。
