iT邦幫忙

2025 iThome 鐵人賽

DAY 18
1
DevOps

GitLab CI 2025:深入玩轉流水線與實戰紀錄系列 第 18

Day18 CI/CD 解題趣-下一階段手動或自動執行,由本階段決定 - 01

  • 分享至 

  • xImage
  •  

這次的鐵人賽系列文章,大致上把 GitLab 13.3 開始到目前 18.3 期間,我覺得比較重要的變化及更新做了一些說明,接下來會進入「解題趣」系列,這系列主要是使用 GitLab CI/CD 至今遇到或聽到看到的一些難題。

這系列的每個題目,來源可能來自 stackoverflow 上的問題、工作中實際遇到的案例或朋友的詢問,題目有時候是 GitLab CI/CD 目前還不容易達成需求,或需要轉變換一下思維邏輯的題目。這些題目不一定會在一篇的篇幅內,就列出最終的解法,而可能會是一系列的實驗、驗證、測試、歸納的心得,以及特性說明。

首先第一個題目是來自 stackoverflow 上的題目「How to set a job to manual based on previous stage failure?」,稍微總結一次題目,其問題主要想了解的是:「當流水線目前階段的工作發生錯誤時,下一階段的工作是否可以改為手動啟動?」

這個問題合理嗎?

這個問題合理嗎?可以運用在什麼樣的場景?現行的 GitLab CI 遇到什麼樣的問題?以及在現階段 GitLab CI 設計的結構下又可以如何達成這樣的需求?

這樣的需求,可能運用在什麼樣的場景?在原始題目的描述中,問題需求者提到了他的場景,他的流水線會控制一些主機的開機(Start)、使用、關閉(Teardown)及消滅(Destroy)程序,可以想像就是開機、使用、關閉、消滅四個階段(Stage)。

開機(Start) -> 使用 -> 關閉(Teardown) -> 消滅(Destroy)

當關閉程序執行成功時,下一個階段會進行主機的消滅(Destroy)程序,可是當執行關閉程序時,發生失敗,就希望後續主機自動消滅便改為手動進行。因為關閉失敗可能有些資源需要人工介入確認後,才能再繼續後續的消滅程序。主機停機程序以及消滅程序這樣的場景中,需要特定情況才改為手動執行,題目就蠻合理的。

可能可以怎麼實作?

稍微了解題目後,會發現題目的目的在於需要「依據特定階段工作執行狀態,來決定下一階段的工作為自動啟動或手動啟動」,於是根據這個特徵開始找尋解決方案。

嘗試一: 透過 GitLab CI/CD 的 rules:when 語法

第一個想法可能會想使用 GitLab CI 提供的 rules:when 語法來解決,透過現行 rules:when 六個屬性:

when 屬性 說明
on_success 上一工作成功時
manual 手動執行
always 總是執行
on_failure 上一工作失敗時
delayed 延遲執行
never 從不執行

目前題目的特徵,像是 when: on_failure && manual,兩個屬性來做 AND 的條件操作,也就是:「當上一工作失敗時,且設定為手動執行模式時」執行。但截至 GitLab CI 現行版本 18.3 中,無論是 rules:whenwhen,上面提到的六種屬性,均無法同時存在。因此這個題目並無法簡單的在一個 Job 裡頭直接透過 GitLab CI 的語法辦到。

嘗試二:利用 pre-defined variables 中的 CI_JOB_STATUS

Predefined variables 中,定義了 CI_JOB_STATUS 屬性,其特性是,可以在 after_script 的段落中,判斷到目前的 Job,在 script 的段落是否執行正確,當正確執行時為 success 當錯誤執行時為 failed,當被關閉時為 canceled,且無論 script 執行是否正確 after_script 都會執行。

因此可能可以透過這個屬性特性,當偵測到錯誤時,再透過 artifacts:reports:dotenv 可傳遞的變數設置,傳遞到往後的 stage,供後續 stage 的工作判斷。

實驗案例撰寫:

stages:
  - "teardown"
  - "cleanup"

default:
  image: ubuntu:24.04 #使用用 IMAGE 較小,image 載入速度較快

teardown job:
  stage: teardown
  variables:
    IS_MANUAL_START: "false"
  script:
    - echo "run teardown job and exit 10"
#    - exit 10
  after_script:
    - echo "in after script 01"
    - if [[ $CI_JOB_STATUS == "failed" ]]; then IS_MANUAL_START="true"; fi;
    - echo "IS_MANUAL_START=$IS_MANUAL_START" >> cleanup.env
    - echo "in after script 02"
  artifacts:
    reports:
      dotenv: cleanup.env

cleanup job:
  stage: cleanup
  needs: 
    - teardown job
  rules:
    - if: $IS_MANUAL_START == "true"
      when: manual
    - when: always
  script:
    - echo "IS_MANUAL_START = $IS_MANUAL_START"
    - echo "run cleanup job"

實驗結果

當在下一個工作判斷變數時發現無論如何,工作並不會手動執行,但在 script 中又可以看到變數真的有如預期的設置。不如預期的執行,但這是 GitLab 的執行特徵,在 GitLab Server 要建立整個 Pipeline 前,就 已經 透過工作中的 rules 來判斷,該 Job 是否該建立、是否該做什麼,但由於透過 artifacts:reports:dotenv 所傳遞的變數,是在工作建立「後」才建立,因此 GitLab Server 無法判斷,導致永遠使用 rule:when: always 建立工作。

因此,這次的實驗假設不成立,無法解決原始問題。

階段總結

今天做了兩個嘗試,第一是透過 GitLab CI/CD 的 rules:when,但目前這個特性無法採用連集,而第二個嘗試,想透過 CI_JOB_STATUS 的屬性,並透過 artifacts:reports:dotenv 來傳遞變數到下一個階段,但由於 Pipeline 的 Job 是否執行是在 Pipeline 建立前就定義,因此無法滿足。透過這兩個嘗試,其實可以更深入的理解 GitLab 的細節特性特徵,接下來,會持續完成這個題目(其實最終我認為比較適用的方法已經在 stackoverflow 上可以看到)。我是墨嗓(陳佑竹),期待這次的內容能帶給你實用的啟發與幫助。

參考範例

參考連結


上一篇
Day17 - 讓 CI/CD YAML 的 needs 當 Job 存在的時候才 needs
下一篇
Day19 - CI/CD 解題趣-下一階段手動或自動執行,由本階段決定 - 02
系列文
GitLab CI 2025:深入玩轉流水線與實戰紀錄19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言