CI/CD 十關

LV.2/10

Stages 與 Jobs

用 stages 排出建置、測試、部署的順序,學會平行 job 與允許失敗

基礎約 15 分鐘stages、default、allow_failure、.pre/.post

學習目標

  • 用 stages 決定執行順序。
  • 知道同一個 stage 的 job 會平行執行。
  • 會用 default、before_script、after_script、allow_failure、when: always。

觀念

.pre      build        test                    deploy        .post
prepare → build-app → test-unit            → deploy-demo → cleanup
                      test-lint
                      test-experimental(允許失敗)
  • 前一個 stage 的 job 全部成功,下一個 stage 才開始。
  • .pre、.post 是內建階段,不用寫在 stages 裡。
  • default 是所有 job 的共用設定;job 自己寫了同一個鍵就以 job 為準。

範例解說

設定用途
before_script每個 job 在 script 前先跑,適合印資訊、裝工具
after_scriptscript 成功或失敗都會跑,適合清理。它是另一個 shell,變數不會延續
allow_failure: { exit_codes: [42] }只有結束碼 42 當成警告(黃色驚嘆號),pipeline 仍然通過
when: always前面失敗也照跑
timeout單一 job 的執行上限
interruptible: true有新 commit 時可以取消舊的 job

allow_failure: true 會放過所有失敗,容易把真的問題藏起來;能指定結束碼就指定結束碼。

動手做

  1. push 後看 pipeline 圖:test 欄有三個 job 同時跑。
  2. 把 test-experimental 的 exit 42 改成 exit 1,pipeline 會失敗、deploy-demo 不會執行,但 cleanup 仍然會跑。
  3. 在 stages 裡把 test 移到 build 前面,觀察順序改變。

常見錯誤

  • job 寫了 stage: tests,但 stages 裡是 test:pipeline 會直接報錯。
  • 以為 after_script 失敗會讓 job 失敗:不會,它的失敗只會出現在紀錄裡。

下一關

Lv.3 讓 job 之間傳遞檔案:artifacts。

範例檔案

資料夾 lv02-stages-jobs/ 的全部檔案。.gitlab-ci.yml 可以直接複製到自己的專案根目錄執行。

lv02-stages-jobs/.gitlab-ci.yml
lv02-stages-jobs/.gitlab-ci.yml
# Lv.2 Stages 與 Jobs
# 同一個 stage 的 job 平行執行;前一個 stage 全部成功,下一個 stage 才開始。
# .pre 與 .post 是內建階段,一定排在最前與最後,不用寫進 stages。

stages:
  - build
  - test
  - deploy

# default:所有 job 共用的設定,job 自己有寫就以 job 為準
default:
  image: alpine:3.22
  before_script:
    - echo "[$CI_JOB_STAGE] $CI_JOB_NAME 開始"
  # 推了新 commit 時,舊 pipeline 裡還沒跑完的 job 可以被取消,省 runner 時間
  interruptible: true

prepare:
  stage: .pre
  script:
    - echo "檢查工具版本"
    - sh --help 2>&1 | head -1

build-app:
  stage: build
  timeout: 5 minutes
  script:
    - echo "編譯中……"
    - sleep 3
    - echo "編譯完成"

test-unit:
  stage: test
  script:
    - echo "單元測試:3 項通過"

test-lint:
  stage: test
  script:
    - echo "風格檢查:沒有問題"

# 允許失敗:只有結束碼 42 會被當成「警告」,其他結束碼一樣算失敗
test-experimental:
  stage: test
  allow_failure:
    exit_codes: [42]
  script:
    - echo "實驗中的測試,失敗不擋 pipeline"
    - exit 42

deploy-demo:
  stage: deploy
  script:
    - echo "部署到示範環境(Lv.9 會用 environment 正式做)"
  # after_script 不論 script 成功或失敗都會跑,適合清理
  after_script:
    - echo "清理暫存檔"

cleanup:
  stage: .post
  # when: always:前面就算失敗也會跑
  when: always
  script:
    - echo "pipeline 結束,狀態彙整完成"