iT邦幫忙

2025 iThome 鐵人賽

DAY 19
0
DevOps

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

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

  • 分享至 

  • xImage
  •  

在上一篇的內容中,進行了兩種嘗試,但基於 GitLab 的特性,都無法滿足需求「依據特定階段工作執行狀態,來決定下一階段的工作為自動啟動或手動啟動」,接下來會繼續進行一些嘗試來滿足這個需求:

嘗試三: 透過 Parent-Child 的 Pipeline 結構

在上一個嘗試中由於無法在工作建立之前就決定好變數,因此無法使用 after_script 使用預載變數 CI_JOB_STATUS 的方法來建立變數讓下一個 Stage 根據該變數來決定該手動啟用或直接啟動,因此第二個嘗試決定改為採用 trigger 的模式,動態建立的 pipeline。到工作階段才來建立更新環境有關的 Pipeline 總可以吧?!

實驗案例 GitLab CI/CD YAML 撰寫:

# cleanup.yml 實作子程序依據變數判斷是否要手動啟動

default:
  image: ubuntu:20.04

cleanup job:
  rules:
    - if: $IS_MANUAL_START == "true"
      when: manual
    - when: always
  before_script:
    - echo "IS_MANUAL_START = $IS_MANUAL_START"  
    - if [[ $IS_MANUAL_START == "true" ]]; then echo 'is true'; fi;
    - if [[ $IS_MANUAL_START != "true" ]]; then echo 'is false'; fi;
  script:
    - echo "run cleanup job"

接下來是 .gitlab-ci.yml 的實作:

# .gitlab-ci.yml
default:
  image: ubuntu:24.04

stages:
  - "teardown"
  - "cleanup"

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"
    - if [[ $CI_JOB_STATUS == "failed" ]]; then IS_MANUAL_START="true"; fi;
    - echo "IS_MANUAL_START=$IS_MANUAL_START"
    - echo "IS_MANUAL_START=$IS_MANUAL_START" >> cleanup.env
  allow_failure: true
  artifacts:
    reports:
      dotenv: cleanup.env

cleanup trigger:
  stage: cleanup
  trigger:
    include: cleanup.yml
    forward:
      yaml_variables: true
  variables:
    IS_MANUAL_START: $IS_MANUAL_START

這段 .gitlab-ci.yml 同樣是基於 CI_JOB_STATUS 變數的特性,可以在 after_script 中使用,用以帶入決定自訂變數 IS_MANUAL_START 數值,差別在於,這邊建立工作的方法是透過 trigger 建立 Child Pipeline。

這次的嘗試,結果是可行的。因為 Trigger Child Pipeline,的確有符合上一篇文章中提到的原則,是否要建立 Job 的 rule 必須在 Pipeline 建立前就決定。Trigger Pipeline 在建立 Child Pipeline 時就知道變數的狀態,因此符合。

不過這邊因為透過 after_script 中撰寫 if else 來控制變數,雖然是簡單的 if else 邏輯,但把控制 Pipeline 流程的 if else 放在 Job Script 裡頭,會導致 Pipeline 的邏輯相對的難以理解,是不是有更好的方案呢?

  after_script:
    - echo "in after script"
    - if [[ $CI_JOB_STATUS == "failed" ]]; then IS_MANUAL_START="true"; fi;

嘗試四:透過 when:on_successwhen:on_failure 個別建立 Child Pipeline

首先建立相關的 CI/CD YAML

cleanup job 的模板

# file name: cleanup_job_tmpl.yml

.cleanup_job_tmpl:
  image: ubuntu:20.04
  script:
    - echo "run cleanup job"

自動執行的 cleanup job

# file name: cleanup_auto.yml

include: cleanup_job_tmpl.yml

cleanup_job_auto:
  extends: .cleanup_job_tmpl
  before_script:
    - echo "auto run job"

手動執行的 cleanup job

# file name: cleanup_manual.yml

include: cleanup_job_tmpl.yml

cleanup_job_manual:
  extends: .cleanup_job_tmpl
  when: manual
  before_script:
    - echo "manual run job"

GitLab CI/CD YAML .gitlab-ci.yml

# file name: .gitlab-ci.yml

stages:
  - "teardown"
  - "cleanup"

default:
  image: ubuntu:24.04

teardown job:
  stage: teardown
  script:
    - echo "run teardown job and exit 10"
    - exit 10
  artifacts:
    reports:
      dotenv: cleanup.env  

cleanup_auto_trigger:
  stage: cleanup
  when: on_success #(default on_success)
  trigger:
    include: cleanup_job_auto.yml

cleanup_manual_trigger:
  stage: cleanup
  when: on_failure
  trigger:
    include: cleanup_job_manual.yml

這個實驗結果,確認,也是可行的。如下圖,當把 exit 10 註解移除時,會發生錯誤,如下圖,會產出一個需要手動啟動的 Downstream Pipeline。

Job When exit 10

同樣的把 exit 10 移除後,則可以自動的啟動 Downstream Pipeline:

Job when success

總結

在 YAML 的工作條件中,直接使用 when 來依據上一段工作的成功與否定義預計要 trigger 的 child pipeline,可以發現,無論是建立自動啟動工作的 cleanup_auto_trigger 或是需要手動啟動工作的 cleanup_manual_trigger 關鍵點沒有邏輯判斷,都相對的更好讀一些,且直接在 Job 上描述啟動條件,相對容易理解,我個人認為,這個解決方案,應該會比第三個嘗試更好一些,正在讀這篇內容的你,覺得呢?有沒有更好的方案可以建議?

我是墨嗓(陳佑竹),期待這次的內容能帶給你實用的啟發與幫助。

參考範例

參考連結


上一篇
Day18 CI/CD 解題趣-下一階段手動或自動執行,由本階段決定 - 01
系列文
GitLab CI 2025:深入玩轉流水線與實戰紀錄19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言