GitLab CI 實戰(踩坑)筆記

本文目錄
  1. GitLab CI 資料夾結構設計
  2. 在 .gitlab/.default.gitlab-ci.yml 定義要執行 pipeline 的 Branchs
  3. 根據專案需求定義對應的 Stages
  4. 想在不同 stage 傳遞資料時,artifacts 跟 cache 的使用時機
  5. 讓 stage 下的 job 並行執行 or 順序執行
  6. notify 階段建議要有的資訊
  7. Dockerfile 多階段構建
  8. 其他的坑(套件安裝、相容性、單元測試)

GitLab CI 是 GitLab 的內建工具,每次 Push 都會觸發一次腳本執行,內容通常涵蓋測試、編譯、部署等一系列自定義內容。

這篇文章會分享設計上要注意的細節,以及實戰過程踩過的坑,不會特別說明基礎資訊,想更深入理解的朋友可以參考官網文件;如果讀者有更好的方案,或對名詞有更精準的定義,歡迎留言分享。

GitLab CI 實戰(踩坑)筆記(圖 1)

文章大綱

▋ GitLab CI 資料夾結構設計
▋ 在 .gitlab/.default.gitlab-ci.yml 定義要執行 pipeline 的 Branchs
▋ 根據專案需求定義對應的 Stages
▋ 想在不同 stage 傳遞資料時,artifacts 跟 cache 的使用時機
▋ 讓 stage 下的 job 並行執行 or 順序執行
▋ notify 階段建議要有的資訊
▋ Dockerfile 多階段構建
▋ 其他的坑(套件安裝、相容性、單元測試)

GitLab CI 資料夾結構設計

Project
├── .gitlab-ci.yml
└── .gitlab
    ├── stages
    │   ├── 1.xxx.yml
    │   └── 2.xxx.yml
    ├── .default.gitlab-ci.yml
    └── docker-bake.hcl

下面說明一下資料夾結構下各檔案要負責的任務:

  • .gitlab-ci.yml: 定義有要執行的 stages,以及參考的 yml 檔案(ex: .gitlab/.default.gitlab-ci.yml)。
  • .gitlab: 存放 GitLab 設定檔的資料夾。
  • .gitlab/stages: 存放各 stage 的資料夾,讓邏輯更容易維護。
  • .gitlab/stages/xxx.yml: 定義 stage 下各 jobs 要執行的任務。
  • .gitlab/.default.gitlab-ci.yml: 用來定義默認的設定,避免重複性的工作(ex: 設定通用的 variables、定義要執行 pipeline 的 branchs)。
  • .gitlab/docker-bake.hcl: 定義 Build Docker Image 的資訊(ex: 支援多平台、傳遞參數)。

在 .gitlab/.default.gitlab-ci.yml 定義要執行 pipeline 的 Branchs

僅管我們期待每次 Push 一版都會觸發 pipeline,但有時也會有一些例外狀況(ex: 需要高頻率 Push 測試一些特殊功能)。

以下面的設計來說,就是僅允許「merge_request_event」以及「release/、hotfix/、feature/*」,還有 Default Branch(ex: master、develop)會觸發 pipeline。

workflow:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH =~ /^release\/.*$/'
    - if: '$CI_COMMIT_BRANCH =~ /^hotfix\/.*$/'
    - if: '$CI_COMMIT_BRANCH =~ /^feature\/.*$/'
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'

根據專案需求定義對應的 Stages

筆者習慣設計下面 5 個 Stages:

  • init: 在這個階段做套件安裝的任務(ex: npm install)。
  • analysis: 如果 init 順利才會進入這個階段,會在這裡進行單元測試(test)、Coding Style 檢查(lint),並將對應的 report 保存到 artifacts 當中。
  • build_image: 如果前面都通過才會 Build Docker Image,並將 $TARGET_IMAGE:$TAG 保存到 artifacts/tags.txt 當中(要在 notify 階段使用)。
  • notify: 我將它設定為 always 執行,用來傳送 pipeline 成功/失敗的訊息到對應的 Chanel(ex: Zoom、Teams、Line)。
  • deploy: 根據實際需求設計部署流程。

想在不同 stage 傳遞資料時,artifacts 跟 cache 的使用時機

上個 stage 做完的事情,在下個 stage 是不會知道細節的。

想要傳遞資訊就需要透過 artifacts 或 cache,而這兩者的用途不太一樣:

  • artifacts: 記錄這次 pipeline 獨有的資訊,像是 test report、image_id 這類的,建議要設定對應的 expire_in 時間,否則資料會永久保存消耗硬碟空間。
analysis:
  artifacts:
    paths:
      - reports
    expire_in: 1 day
  • cache: 這個專案經常使用的資料,比如 node_modules 這類保存套件的資料夾。
analysis:
  cache:
    key: "${CI_PROJECT_PATH_SLUG}"
    paths:
      - node_modules

讓 stage 下的 job 並行執行 or 順序執行

如果沒有特別設計,stage 下的 job 默認都是並行執行的(比如 unit test & lint 可以同時進行);如果想要順序執行,可以透過 needs 來設定,範例如下:

job1:
  stage: build
  script:
    - echo "Executing job1"
job2:
  stage: build
  script:
    - echo "Executing job2"
  needs:
    - job1  # 等待 job1 完成後執行

notify 階段建議要有的資訊

GitLab CI 通常要跑幾分鐘的時間(通常跟 unit test 多寡有關),所以要設計 notify 的機制來傳遞資訊,建議包含的內容如下:

  • project: $PROJECT_NAME,方便了解執行的專案。
  • branch: $CI_COMMIT_REF_NAME,了解哪個 branch 更新了。
  • result: 會包含成功與失敗的詳細資訊。
  • pipeline_link: $PIPELINE_LINK,出問題時點擊連結可以看到最直接的資訊。
  • image_id: 從 artifacts 裡面讀取。

Dockerfile 多階段構建

下面用一個範例來說明如何用多階段構建(multi-stage build)來減少 Docker Image 大小並提高效率(COPY –from=builder 的作用是從第一階段複製文件到第二階段)。

# 第一階段:使用 Node.js 安裝套件,並進行打包
FROM node:23.3-alpine as builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build

# 第二階段:使用 Nginx 部署靜態文件
FROM nginx:alpine3.20
COPY --from=builder /app/dist /usr/share/nginx/html
WORKDIR /usr/share/nginx/html
COPY ./build/nginx/default.conf /etc/nginx/conf.d/default.conf

透過這個方案,最終的 Image 只有靜態文件跟 Nginx,不包含 Node.js 開發工具;不但減少 Image 大小,還減少了潛在攻擊面向。


其他的坑(套件安裝、相容性、單元測試)

  • 套件無法順利安裝: 如果套件是經由私有庫來安裝的,就需要設定對應的網路環境;如果在 Dockerfile 裡面安裝,請記得將 .npmrc 這類設定 COPY 到對應的位置。
  • qemu-user-static 相容性錯誤: 有些專案需要指定對應的 platform 才能順利 build 出來(Dockerfile from 的 image 可能僅支持 arm 或 amd)。
  • 單元測試錯誤突然暴增: 如果在 local 環境測試起來正常,但在 GitLab CI 時出現錯誤,那通常是「非同步」的問題,可以先用 await 拉長等待時間,並搭配 log 來釐清狀況。

有段時間沒發純技術的文章了,希望能幫助到有相關需求的朋友們,也歡迎大家分享自己在 GitLab CI 的使用經驗。

Talk

留言討論

留言載入中…