一. 设计思路
构建一个 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: lint
image:
name: alpine/helm:3.12.3
entrypoint: [""] # 覆盖默认entrypoint,避免直接执行helm
before_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_image
image: docker:24.0.5
services:
- 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}:latest
only:
- main # 仅主分支触发镜像构建
- merge_requests # 合并请求时也构建(可选)
# 阶段3:打包并推送Helm Chart到私有仓库
package_chart:
stage: package_chart
image: alpine/helm:3.12.3
before_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.yaml
script:
# 打包Chart(版本号=Git Commit哈希)
- helm package ${CHART_DIR} --version ${CI_COMMIT_SHORT_SHA}
# 推送Chart到私有仓库
- helm push ${APP_NAME}-${CI_COMMIT_SHORT_SHA}.tgz myrepo
only:
- main
# 阶段4:测试环境部署(自动执行)
test_deploy:
stage: test_deploy
image:
name: alpine/helm:3.12.3
entrypoint: [""]
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 update
script:
# 部署到测试环境(命名空间: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/health
only:
- main
# 阶段5:生产环境部署(手动触发)
prod_deploy:
stage: prod_deploy
image:
name: alpine/helm:3.12.3
entrypoint: [""]
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 update
script:
# 部署到生产环境(命名空间:prod)
- |
if helm list -n prod | grep -q ${APP_NAME}-prod; then
helm upgrade ${APP_NAME}-prod myrepo/${APP_NAME} \
--version ${CI_COMMIT_SHORT_SHA} \
-n prod \
-f ${PROD_VALUES}
else
helm 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=10m
when: manual # 手动触发,避免误操作
only:
- main
environment:
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_deploy
image: alpine/helm:3.12.3
script:
- helm rollback ${APP_NAME}-prod 1 -n prod # 回滚到上一版本
when: manual
environment:
name: production
2. 多集群部署
如需部署到多个生产集群,可通过变量区分 KUBECONFIG,例如:
prod_deploy_cluster1:
script:
- export KUBECONFIG=${KUBECONFIG_CLUSTER1} # 集群1的kubeconfig
- helm upgrade ... # 部署到集群1
prod_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 # 发现高危漏洞则失败