DevOps篇之通过GitLab CI 流水线实现k8s集群中helm应用发布

发布于:2025-09-02 ⋅ 阅读:(22) ⋅ 点赞:(0)

一. 设计思路

构建一个 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 的校验、构建、测试和部署。
在这里插入图片描述

三. 实现方案

以下是详细实现方案:

一. 环境准备

  1. 工具与依赖
  • GitLab Runner:需配置具有docker执行权限的 Runner(用于构建镜像和执行 Helm 命令)。【执行机器】
  • 基础镜像:Runner 使用包含helm、kubectl、docker的镜像(如alpine/helm:3.12.3 + 额外工具)。
  • K8s 集群访问:GitLab 项目需配置 K8s 集群访问凭证(通过 GitLab 集成或 CI 变量注入)。
  • 容器仓库:如 Harbor、Docker Hub,用于存储应用镜像。
  1. 凭证管理(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  # 发现高危漏洞则失败

网站公告

今日签到

点亮在社区的每一天
去签到