歡迎使用流水線指令-矩陣
- 2020 年 2 月 14 日
- 筆記
我經常發現自己需要在一堆不同的配置上執行相同的操作。到目前為止,意味着我需要在流水線上的同一階段製作多個副本。當我需要修改時,必須在整個流水線的多個地方做相同的修改。對於一個更大型的流水線來說,即便維護很少的配置也會變得困難。聲明式流水線1.5.0-beta1(可以從 Jenkins 實驗性更新中心獲取)添加了一個新的 matrix
部分,該部分能讓我一次指定一個階段列表,然後在多個配置上並行運行同一列表。讓我們來看一看!
單一配置流水線
開始我會使用一個帶有構建和測試階段的簡單流水線。我使用 echo
步驟作為構建和測試行為的佔位符。
Jenkinsfile
pipeline { agent none stages { stage('BuildAndTest') { agent any stages { stage('Build') { steps { echo 'Do Build' } } stage('Test') { steps { echo 'Do Test' } } } } } }
多平台與瀏覽器的流水線
我更喜歡在多系統以及瀏覽器結合的情況下執行我的構建和測試。新的 metrix
指令能讓我定義一個 axes
的集合。每個 axis
有一個 name
以及包含了一個或多個 values
的列表。當流水線運行的時候,Jenkins 會將這些託管過來並將每個「軸」上所有可能值的組合運行在我的階段內。一個「矩陣」上所有的元素都是並行運行的(只受限於可用的節點數量)。我的「矩陣」有兩個「軸」: PLATFORM
和 BROWSER
。PLATFORM
有三個值 BROWSER
有四個值,所以我的階段會運行12個不同的組合。我已經修改了我的 echo
步驟用來使用每個元素中「軸」的值。
Jenkinsfile
pipeline { agent none stages { stage('BuildAndTest') { matrix { agent any axes { axis { name 'PLATFORM' values 'linux', 'windows', 'mac' } axis { name 'BROWSER' values 'firefox', 'chrome', 'safari', 'edge' } } stages { stage('Build') { steps { echo "Do Build for ${PLATFORM} - ${BROWSER}" } } stage('Test') { steps { echo "Do Test for ${PLATFORM} - ${BROWSER}" } } } } } } }
日誌輸出(部分內容)
... [Pipeline] stage [Pipeline] { (BuildAndTest) [Pipeline] parallel [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'edge') (hide) [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'edge') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'edge') ... Do Build for linux - safari Do Build for linux - firefox Do Build for windows - firefox Do Test for linux - firefox Do Build for mac - firefox Do Build for linux - chrome Do Test for windows - firefox ...
排除無效的組合
現在我已經創建一個基本的「矩陣」了,我注意到我有一些無效的組合。Edge 瀏覽器只在 Windows 系統上運行以及沒有 Linux 版本的 Safari。我可以使用 exclude
命令去掉我的「矩陣」中無效的元素。每個 exclude
含有一個或多個帶有 name
和 values
的 axis
指令。一個 exclude
中的 axis
指令會生成一組組合(類似於生成「矩陣」中的元素)。「矩陣」中的元素匹配一個 exclude
中所有需要從「矩陣」中移出的值。如果我有不止一個 exclude
指令,每個都將分別評估來移除元素。當需要處理一個長的排除列表時,我可以使用 notValues
而不是 values
去指定「軸」中我們不想排除的值。是的,這有點雙重否定的意思,所以會有一點困惑。我只會在我真正想用的時候才會用它。下面的流水線示例,我排除了 linux, safari
的組合同樣我排除了除了 windows
之外的其他平台 和 edge
瀏覽器的組合。
本流水線使用兩個「軸」,但是沒有使用 axis
指令數量的限制。同樣,在這個流水線里每個 exclude
指定這兩個「軸」的值,但是這不是必須的。如果我們想只在「linux」元素中運行,我們需要使用以下的 exclude
:
exclude { axis { name 'PLATFORM' notValues 'linux' } }
pipeline { agent none stages { stage('BuildAndTest') { matrix { agent any axes { axis { name 'PLATFORM' values 'linux', 'windows', 'mac' } axis { name 'BROWSER' values 'firefox', 'chrome', 'safari', 'edge' } } excludes { exclude { axis { name 'PLATFORM' values 'linux' } axis { name 'BROWSER' values 'safari' } } exclude { axis { name 'PLATFORM' notValues 'windows' } axis { name 'BROWSER' values 'edge' } } } stages { stage('Build') { steps { echo "Do Build for ${PLATFORM} - ${BROWSER}" } } stage('Test') { steps { echo "Do Test for ${PLATFORM} - ${BROWSER}" } } } } } } }
日誌輸出(部分內容)
... [Pipeline] stage [Pipeline] { (BuildAndTest) [Pipeline] parallel [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'edge') ... Do Build for linux - firefox ...
運行時控制元素行為
在 matrix
指令中同樣我可以添加「每個-元素」指令。這些相同的指令我可以添加到一個 stage
中讓我可以控制「矩陣」中每一個元素的行為。這些指令可以從它們的元素的「軸」中獲取值作為輸入,允許我自定義每一個元素的行為以匹配它的「軸」的值。在我的 Jenkins 服務器中我已經配置了各個節點並為各個節點配置了系統名稱的標籤(「linux-agent」,「windows-agent」,和「mac-agent」 )。為了在正確的操作系統上運行「矩陣」中的元素,我配置了 Groovy 字符模板為元素配置標籤。
matrix { axes { ... } excludes { ... } agent { label "${PLATFORM}-agent" } stages { ... } // ... }
有時我通過 Jenkins 的網頁手動運行流水線任務。當我這樣做時,我能夠只選擇一個運行的平台。 axis
和 exclude
指令定義了一個組成「矩陣」的一組靜態的元素。這一組合的集合在運行開始之前就被創建出來,也早於任何的參數獲取。也就意味着我不能在任務已經開始後從「矩陣」上添加或者移除元素。另一方面,「每個-元素」指令,在運行時會被評估。我可以使用「每個-元素」 metrix
中的 when
指令來控制「矩陣」中哪個元素會被執行。我添加了一個帶有平台列表的 choice
字段,以及在 when
指令添加了判斷,這樣會確定是所有的平台都執行還是只執行我指定的平台的元素。
pipeline { parameters { choice(name: 'PLATFORM_FILTER', choices: ['all', 'linux', 'windows', 'mac'], description: 'Run on specific platform') } agent none stages { stage('BuildAndTest') { matrix { agent { label "${PLATFORM}-agent" } when { anyOf { expression { params.PLATFORM_FILTER == 'all' } expression { params.PLATFORM_FILTER == env.PLATFORM } } } axes { axis { name 'PLATFORM' values 'linux', 'windows', 'mac' } axis { name 'BROWSER' values 'firefox', 'chrome', 'safari', 'edge' } } excludes { exclude { axis { name 'PLATFORM' values 'linux' } axis { name 'BROWSER' values 'safari' } } exclude { axis { name 'PLATFORM' notValues 'windows' } axis { name 'BROWSER' values 'edge' } } } stages { stage('Build') { steps { echo "Do Build for ${PLATFORM} - ${BROWSER}" } } stage('Test') { steps { echo "Do Test for ${PLATFORM} - ${BROWSER}" } } } } } } }
如果我從 Jenkins 的 UI 頁面上運行流水線設置 PLATFORM_FILTER
字段為 mac
,我會得到如下的輸出:
日誌輸出(部分內容 – PLATFORM_FILTER = 『mac』)
... [Pipeline] stage [Pipeline] { (BuildAndTest) [Pipeline] parallel [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'firefox') [Pipeline] { (Branch: Matrix - OS = 'linux', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'chrome') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'mac', BROWSER = 'safari') [Pipeline] { (Branch: Matrix - OS = 'windows', BROWSER = 'edge') ... Stage "Matrix - OS = 'linux', BROWSER = 'chrome'" skipped due to when conditional Stage "Matrix - OS = 'linux', BROWSER = 'firefox'" skipped due to when conditional ... Do Build for mac - firefox Do Build for mac - chrome Do Build for mac - safari ... Stage "Matrix - OS = 'windows', BROWSER = 'chrome'" skipped due to when conditional Stage "Matrix - OS = 'windows', BROWSER = 'edge'" skipped due to when conditional ... Do Test for mac - safari Do Test for mac - firefox Do Test for mac - chrome
重要 在 DevOps World | Jenkins World 2019 「聲明式流水線2019:知識點,技巧,以及接下來的事情」中與我一起參與。我會回顧過去的一年有哪些加入到了流水線(包括「矩陣」)以及探討一些關於流水線下一步走向的想法。
結論
這篇博客裏面,我們已經看到了怎樣使用 matrix
指令來構成簡潔但又強大的聲明式流水線。同樣的一個不帶有 matrix
的流水線會容易一些,但會消耗更多的時間同樣也會更難理解和維護。
鏈接
- Jenkins 實驗性更新中心
- 使用 Jenkins 實驗性更新中心
譯者:s1mple_zj