哈囉大家好,歡迎來到 CI/CD 自動化的第三天!
在昨天的 Day 19,我們成功地在 Kubernetes 叢集中,部署並註冊了一位隨時待命的 GitLab Runner。它現在正等待著,準備接收來自 GitLab 的任何指令。
今天,我們的任務就是為它提供一份清晰的工作指示。這份指示,就是我們專案中最重要的自動化藍圖 —— .gitlab-ci.yml
檔案。
我們今天會學習設定檔內的語法,先專注於實現 CI (持續整合) 的部分:
.gitlab-ci.yml
的基本結構.gitlab-ci.yml
是一個放置在你專案根目錄下的 YAML 檔案。GitLab 會在每一次 git push
時,自動讀取這個檔案,並根據裡面的內容來執行 CI/CD 流程。
我們先來看看這份設定檔的整體結構與一些重要的「全域設定」。
# .gitlab-ci.yml
# --- 全域變數定義 ---
variables:
# Harbor Registry 設定
HARBOR_REGISTRY: "harbor.rehearaudio.com"
HARBOR_PROJECT: "rehear-dev"
# Docker Image 名稱模板
BACKEND_IMAGE: "${HARBOR_REGISTRY}/${HARBOR_PROJECT}/ota-backend"
FRONTEND_IMAGE: "${HARBOR_REGISTRY}/${HARBOR_PROJECT}/ota-frontend"
# 使用 GitLab 預定義變數,讓每個 commit 都有唯一的 Image Tag
IMAGE_TAG: "${CI_COMMIT_SHORT_SHA}"
# --- Pipeline 階段定義 ---
stages:
- test
- build
- deploy:dev
- deploy:staging
- deploy:prod
# ... 後續是各個 Job 的定義 ...
variables
:定義了可以在所有 Job 中共用的全域變數。這讓我們可以集中管理 Image 名稱、倉庫位址等資訊,非常方便。$CI_COMMIT_SHORT_SHA
是 GitLab 提供的預定義變數,代表當次 commit 的前 8 位 hash 值。stages
:我們定義了 test
, build
, deploy:dev
等多個階段,並規定了它們的執行順序。今天,我們將專注於前兩個階段。現在,我們在 stages
定義的下方,加入我們的 test
任務。一個好的 CI 流程,第一步永遠是確保程式碼的品質。
# .gitlab-ci.yml (接續)
# --- 測試階段 ---
test:backend:
stage: test
image: golang:1.21 # 為 Go 專案選擇合適的執行環境
tags:
- docker # 選擇我們在 K8s 中設定的 Runner
before_script: # 在主要 script 執行前的前置作業
- cd backend
script:
- go mod download
- go test -v ./...
rules: # 定義此 Job 何時被觸發
- if: $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "develop"
test:frontend:
stage: test
image: node:18-alpine
tags:
- docker
before_script:
- cd frontend
script:
- npm ci
- npm run lint
- npm run type-check
rules:
- if: $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "develop"
這段設定很直觀:
image
: 我們為不同任務選擇了最合適的 Docker Image 作為執行環境 (golang
vs. node
)。script
: 定義了該任務需要執行的核心指令,例如跑測試或語法檢查。rules
: 讓我們可以精確控制 Job 的觸發時機。這裡我們設定為:只有當程式碼被推送到 main
或 develop
分支時,才執行這些任務。如果測試失敗,Pipeline 就會中止,確保有問題的程式碼不會被建置。當所有測試都通過後,下一步就是將我們的程式碼,建置成可部署的 Docker Image。
YAML
`# .gitlab-ci.yml (接續)
# --- 建置階段 ---
build:backend:
stage: build
image:
name: gcr.io/kaniko-project/executor:v1.19.0-debug # 使用 Kaniko 來建置 Image
entrypoint: [""] # 覆寫預設的 entrypoint
tags:
- docker
script:
# 準備 Kaniko 需要的 Docker 認證檔,指向我們的 Harbor
- mkdir -p /kaniko/.docker
- echo "{\"auths\":{\"${HARBOR_REGISTRY}\":{\"auth\":\"$(echo -n ${HARBOR_USERNAME}:${HARBOR_PASSWORD} | base64)\"}}}" > /kaniko/.docker/config.json
# 執行 Kaniko executor
- /kaniko/executor
--context ${CI_PROJECT_DIR}/backend
--dockerfile ${CI_PROJECT_DIR}/backend/Dockerfile
--destination ${BACKEND_IMAGE}:${IMAGE_TAG} # 推送到 Harbor
--cache=true # 啟用快取
rules:
- if: $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "develop"`
build:frontend
的任務與此類似,只是 context
和 destination
不同。
你可能會問,為什麼不直接用 docker build
指令?
docker build
,會涉及到複雜的 Docker-in-Docker (dind) 設定,既不安全也不高效。script
:我們不再執行 docker build
,而是執行 Kaniko 的 /kaniko/executor
。我們透過參數告訴它 Dockerfile
的位置 (-dockerfile
)、建置上下文 (-context
),以及最重要的——建置完成後要將 Image 推送到哪裡 (-destination
)。echo "..." > /kaniko/.docker/config.json
這一長串指令,其實只是在動態地產生一個讓 Kaniko 可以登入我們私有 Harbor 倉庫的認證檔案。$HARBOR_USERNAME
和 $HARBOR_PASSWORD
是我們需要在 GitLab 專案中設定的受保護的 CI/CD 變數。設定檔寫好了,現在就是見證奇蹟的時刻!
Settings > CI/CD > Variables
。HARBOR_USERNAME
和 HARBOR_PASSWORD
,並填入你登入 Harbor 的帳號密碼。建議將它們設定為 Protected
和 Masked
,增加安全性。.gitlab-ci.yml
檔案 commit 並 push 到 develop
或 main
分支。Build > Pipelines
,會看到一條新的 Pipeline 已經被觸發!我們的自動化生產線,現在已經成功地將我們的程式碼,轉化成了存放在 Harbor 倉庫中的、可隨時部署的 Docker Images。
我們已經完成了 CI 的部分。在接下來的文章中,我們就要來完成 CD 的最後一哩路:學習如何撰寫 deploy
階段的 Job,讓 GitLab Runner 自動地使用 Helm
,將這些熱騰騰的新版 Image,部署到我們的 Kubernetes 叢集中! 明天見!