一. 設計思路
構建一個 GitLab CI 流水線,并且要集成到 K8s 集群中的 Helm 應用發布流程。首先,需要了解 GitLab CI 的基本結構,比如.gitlab-ci.yml 文件的配置,包括 stages、jobs、變量設置等。然后,結合之前討論的 Helm 和 K8s 的知識【參考https://blog.csdn.net/xu710263124/article/details/150959212?spm=1001.2014.3001.5501】,將 Helm 的操作(如 lint、template、install、upgrade)整合到流水線中,設計步驟如下:
1、首先,流水線的階段應該包括哪些呢?通常會有校驗(lint)、構建鏡像、打包 Chart、測試部署、正式部署等階段。需要確保每個階段的依賴正確,比如只有校驗通過后才能進行構建,測試部署成功后再正式部署。
2、接下來,考慮如何在 GitLab CI 中連接 K8s 集群。GitLab 提供了 Kubernetes 集成,可以通過配置 KUBECONFIG 變量或者使用 GitLab 的 Kubernetes 代理。另外,需要在 GitLab 項目的 CI/CD 變量中存儲必要的憑證,比如 K8s 的 kubeconfig、容器倉庫的認證信息(如 Harbor 或 Docker Hub 的賬號密碼)。
3、然后,Helm 的操作步驟:在校驗階段使用 helm lint 檢查 Chart 的語法;構建階段可能需要構建應用鏡像并推送到倉庫,同時更新 Chart 中的鏡像標簽;測試階段使用 helm upgrade --dry-run 或者在測試集群中實際部署驗證;正式部署階段則根據環境(如 staging、production)進行 helm upgrade 或 install。
4、還要考慮環境分離,比如通過 GitLab 的環境變量和環境配置,區分開發、測試、生產環境,每個環境可能有不同的 values 文件和部署策略。另外,需要處理版本號,通常可以使用 Git 的 commit hash 或標簽作為鏡像和 Chart 的版本,確保可追溯。
5、安全方面,所有敏感信息(如 kubeconfig、倉庫密碼)都應該存儲在 GitLab 的 CI/CD 變量中,避免明文出現在配置文件中。同時,權限控制方面,GitLab 的 Service Account 在 K8s 中應只授予必要的權限,遵循最小權限原則。
6、可能還需要集成測試步驟,比如部署后檢查 Pod 狀態、執行健康檢查等,確保應用正常運行。如果部署失敗,流水線應該能夠捕獲錯誤并通知相關人員,可能還需要自動回滾的機制,但初期可以先實現手動回滾或通知。
7、最后,編寫.gitlab-ci.yml 文件時,要注意使用合適的鏡像(如包含 helm、kubectl、docker 的鏡像),定義變量,設置每個 job 的腳本,以及階段之間的依賴關系。確保流水線能夠自動執行從代碼提交到應用部署的整個流程,并且每個步驟可監控、可追溯。
二. 實現方案
構建 GitLab CI 流水線并集成 K8s 集群的 Helm 應用發布流程,可實現從代碼提交到應用部署的全自動化,核心是通過
.gitlab-ci.yml定義流水線階段,結合 GitLab 與 K8s 的認證集成,完成 Helm Chart 的校驗、構建、測試和部署。
三. 實現方案
以下是詳細實現方案:
一. 環境準備
- 工具與依賴
- GitLab Runner:需配置具有docker執行權限的 Runner(用于構建鏡像和執行 Helm 命令)。【執行機器】
- 基礎鏡像:Runner 使用包含helm、kubectl、docker的鏡像(如alpine/helm:3.12.3 + 額外工具)。
- K8s 集群訪問:GitLab 項目需配置 K8s 集群訪問憑證(通過 GitLab 集成或 CI 變量注入)。
- 容器倉庫:如 Harbor、Docker Hub,用于存儲應用鏡像。
- 憑證管理(GitLab CI/CD 變量)
在 GitLab 項目的「Settings → CI/CD → Variables」中配置以下敏感信息:
變量名 | 說明 | 類型 |
---|---|---|
KUBECONFIG | K8s 集群的 kubeconfig 內容 | File |
REGISTRY_URL | 容器倉庫地址(如harbor.example.com) | Variable |
REGISTRY_USER | 容器倉庫用戶名 | Variable |
REGISTRY_PASSWORD | 容器倉庫密碼 | Variable |
HELM_REPO_URL | Helm 私有倉庫地址(如需) | Variable |
HELM_REPO_USER | Helm 倉庫用戶名 | Variable |
HELM_REPO_PASSWORD | Helm 倉庫密碼 | Variable |
二. 流水線設計(.gitlab-ci.yml)
流水線分為 5 個核心階段:校驗(Lint)→ 構建鏡像 → 打包 Chart → 測試部署 → 正式部署,支持多環境(測試、生產)分離。
關鍵:GitLab CI集成Helm與K8s的發布流水線
vim .gitlab-ci.yml
stages:- lint # 代碼與Chart校驗- build_image # 構建應用鏡像- package_chart # 打包并推送Helm Chart- test_deploy # 測試環境部署- prod_deploy # 生產環境部署variables:# 應用與鏡像信息APP_NAME: "myapp"IMAGE_NAME: "${REGISTRY_URL}/apps/${APP_NAME}"# 鏡像標簽:使用Git Commit短哈希+流水線ID(確保唯一)IMAGE_TAG: "${CI_COMMIT_SHORT_SHA}-${CI_PIPELINE_ID}"# Helm Chart目錄(默認Chart名稱與應用名一致)CHART_DIR: "./charts/${APP_NAME}"# 測試與生產環境的values文件TEST_VALUES: "./values/test.yaml"PROD_VALUES: "./values/prod.yaml"# 階段1:代碼與Helm Chart校驗
lint:stage: lintimage: name: alpine/helm:3.12.3entrypoint: [""] # 覆蓋默認entrypoint,避免直接執行helmbefore_script:- apk add --no-cache git # 安裝git(用于依賴拉取)- helm dependency update ${CHART_DIR} # 更新Chart依賴script:# 1. 校驗Helm Chart語法- helm lint ${CHART_DIR}# 2. (可選)代碼靜態檢查(如后端用sonar-scanner,前端用eslint)- echo "代碼靜態檢查通過"# 階段2:構建并推送應用鏡像
build_image:stage: build_imageimage: docker:24.0.5services:- docker:24.0.5-dind # Docker-in-Docker服務before_script:# 登錄容器倉庫- docker login -u ${REGISTRY_USER} -p ${REGISTRY_PASSWORD} ${REGISTRY_URL}script:# 構建鏡像(示例為Dockerfile,根據項目調整)- docker build -t ${IMAGE_NAME}:${IMAGE_TAG} -t ${IMAGE_NAME}:latest .# 推送鏡像到倉庫- docker push ${IMAGE_NAME}:${IMAGE_TAG}- docker push ${IMAGE_NAME}:latestonly:- main # 僅主分支觸發鏡像構建- merge_requests # 合并請求時也構建(可選)# 階段3:打包并推送Helm Chart到私有倉庫
package_chart:stage: package_chartimage: alpine/helm:3.12.3before_script:- apk add --no-cache git# 登錄Helm私有倉庫(如Harbor的Chart倉庫)- helm repo add --username ${HELM_REPO_USER} --password ${HELM_REPO_PASSWORD} myrepo ${HELM_REPO_URL}# 更新Chart中的鏡像標簽(替換values中的占位符)- sed -i "s|IMAGE_TAG_PLACEHOLDER|${IMAGE_TAG}|g" ${CHART_DIR}/values.yamlscript:# 打包Chart(版本號=Git Commit哈希)- helm package ${CHART_DIR} --version ${CI_COMMIT_SHORT_SHA}# 推送Chart到私有倉庫- helm push ${APP_NAME}-${CI_COMMIT_SHORT_SHA}.tgz myrepoonly:- main# 階段4:測試環境部署(自動執行)
test_deploy:stage: test_deployimage: name: alpine/helm:3.12.3entrypoint: [""]before_script:# 配置kubectl訪問K8s集群(使用CI變量中的KUBECONFIG)- apk add --no-cache kubectl- export KUBECONFIG=${KUBECONFIG} # KUBECONFIG為File類型變量,自動掛載為文件# 添加Helm倉庫并更新- helm repo add --username ${HELM_REPO_USER} --password ${HELM_REPO_PASSWORD} myrepo ${HELM_REPO_URL}- helm repo updatescript:# 部署到測試環境(命名空間:test)- |if helm list -n test | grep -q ${APP_NAME}-test; then# 已部署則升級helm upgrade ${APP_NAME}-test myrepo/${APP_NAME} \--version ${CI_COMMIT_SHORT_SHA} \-n test \-f ${TEST_VALUES}else# 未部署則安裝helm install ${APP_NAME}-test myrepo/${APP_NAME} \--version ${CI_COMMIT_SHORT_SHA} \-n test \--create-namespace \-f ${TEST_VALUES}fi# 等待部署完成并檢查狀態- kubectl rollout status deployment/${APP_NAME}-test -n test --timeout=5m# 執行健康檢查(示例:訪問/health接口)- kubectl run -n test curl --image=curlimages/curl:latest --rm -it -- curl -f ${APP_NAME}-test:8080/healthonly:- main# 階段5:生產環境部署(手動觸發)
prod_deploy:stage: prod_deployimage: name: alpine/helm:3.12.3entrypoint: [""]before_script:- apk add --no-cache kubectl- export KUBECONFIG=${KUBECONFIG}- helm repo add --username ${HELM_REPO_USER} --password ${HELM_REPO_PASSWORD} myrepo ${HELM_REPO_URL}- helm repo updatescript:# 部署到生產環境(命名空間:prod)- |if helm list -n prod | grep -q ${APP_NAME}-prod; thenhelm upgrade ${APP_NAME}-prod myrepo/${APP_NAME} \--version ${CI_COMMIT_SHORT_SHA} \-n prod \-f ${PROD_VALUES}elsehelm install ${APP_NAME}-prod myrepo/${APP_NAME} \--version ${CI_COMMIT_SHORT_SHA} \-n prod \--create-namespace \-f ${PROD_VALUES}fi# 等待部署完成并檢查狀態- kubectl rollout status deployment/${APP_NAME}-prod -n prod --timeout=10mwhen: manual # 手動觸發,避免誤操作only:- mainenvironment:name: production # GitLab環境跟蹤,支持部署歷史與回滾url: https://prod.example.com # 生產環境訪問地址
四. 核心流程解析
1. 流水線階段說明
- lint:通過helm lint檢查 Chart 語法,更新依賴(如 Redis、MySQL 等),確保 Chart 結構合法。
- build_image:基于代碼構建 Docker 鏡像,推送至私有倉庫,標簽包含 Git Commit 哈希和流水線 ID,確保版本唯一可追溯。
- package_chart:替換 Chart 中鏡像標簽的占位符,打包 Chart 并推送到 Helm 私有倉庫,實現 Chart 的版本化管理。
- test_deploy:自動將 Chart 部署到測試環境,執行滾動更新檢查和健康檢查,驗證應用可用性。
- prod_deploy:手動觸發生產環境部署,使用生產專屬配置(prod.yaml),通過 GitLab 環境跟蹤部署歷史。
2. K8s 與 GitLab 集成關鍵點
- K8s 認證:通過KUBECONFIG變量注入集群訪問憑證,kubectl和helm自動使用該配置訪問集群。
- 環境隔離:測試環境使用test命名空間,生產環境使用prod命名空間,通過不同values文件區分配置(如副本數、資源限制)。
- 安全控制:生產環境部署設為when: manual(手動觸發),避免代碼提交直接影響生產;所有敏感憑證通過 GitLab 變量管理,不暴露在代碼中。
3. Helm 操作核心命令
場景 | 命令示例 | 作用 |
---|---|---|
依賴更新 | helm dependency update ${CHART_DIR} | 拉取 Chart 依賴的子 Chart(如 Redis) |
打包 Chart | helm package ${CHART_DIR} --version x.x | 生成.tgz格式的 Chart 包 |
推送 Chart 到倉庫 | helm push chart.tgz myrepo | 上傳 Chart 到私有倉庫 |
安裝 / 升級 Release | helm install/upgrade | 部署或更新應用到 K8s 集群 |
檢查部署狀態 | kubectl rollout status | 等待 Deployment 就緒,超時則失敗 |
五. 擴展與最佳實踐
1. 回滾機制
在生產環境部署失敗時,可通過 GitLab CI 手動觸發回滾 Job:
prod_rollback:stage: prod_deployimage: alpine/helm:3.12.3script:- helm rollback ${APP_NAME}-prod 1 -n prod # 回滾到上一版本when: manualenvironment:name: production
2. 多集群部署
如需部署到多個生產集群,可通過變量區分 KUBECONFIG,例如:
prod_deploy_cluster1:script:- export KUBECONFIG=${KUBECONFIG_CLUSTER1} # 集群1的kubeconfig- helm upgrade ... # 部署到集群1prod_deploy_cluster2:script:- export KUBECONFIG=${KUBECONFIG_CLUSTER2} # 集群2的kubeconfig- helm upgrade ... # 部署到集群2
3. 集成測試報告
在test_deploy階段后添加測試結果收集,如 JUnit 報告:
test_deploy:script:# ... 部署步驟 ...- kubectl cp -n test <pod-name>:/app/test-results ./reports # 復制測試報告artifacts:reports:junit: ./reports/*.xml # GitLab顯示測試結果
4. 鏡像掃描
在build_image階段添加鏡像安全掃描(如 Trivy),檢測漏洞:
build_image:script:# ... 構建推送鏡像 ...- apk add trivy- trivy image ${IMAGE_NAME}:${IMAGE_TAG} --exit-code 1 # 發現高危漏洞則失敗