DevOps全链路实战 | 第 9 天:CI 与 CD 联动:从代码提交到部署的全自动闭环

发布时间:2026/10/6 12:35:32
DevOps全链路实战 | 第 9 天:CI 与 CD 联动:从代码提交到部署的全自动闭环 第 9/18 天引言在前八天的实践中我们已经分别搭建了 Kubernetes 集群、Harbor 镜像仓库、GitLab 代码平台、GitLab Runner 以及 Argo CD GitOps 引擎。这些组件各自独立运行时已经具备强大能力但 DevOps 的精髓在于联动——只有将 CI持续集成与 CD持续交付串联成一条无人值守的管道才能真正实现”提交代码即部署”的终极目标。今天我们将把 GitLab CI 流水线与 Argo CD GitOps 引擎打通构建一个从代码提交到生产部署的全自动闭环让每一次git push都能自动触发构建、测试、镜像推送、清单更新和集群部署的完整链路。核心概念CI 与 CD 的职责边界在深入实战之前先厘清 CI 与 CD 各自的职责边界这是设计联动架构的基础CI持续集成负责代码编译、单元测试、安全扫描和容器镜像构建。核心产出是可部署的镜像制品存储在 Harbor 中。CD持续交付负责将镜像部署到目标环境。在 GitOps 模式下CD 的核心是维护一份声明式的 Kubernetes 清单仓库Argo CD 持续监听这份清单并与集群实际状态对齐。两者的衔接点是镜像 TagCI 构建出镜像后需要将新的 Tag 写入 CD 仓库的 Deployment 清单中Argo CD 检测到清单变更后自动同步部署。双仓库模型联动架构的核心设计是双仓库模型Two-Repository Model将应用代码与部署清单彻底分离 代码示例# 仓库一应用代码仓库app-repoapp-repo/├── src/ # 应用源码├── Dockerfile # 构建定义├── .gitlab-ci.yml # CI 流水线定义└── tests/ # 测试用例# 仓库二部署清单仓库deploy-repo / GitOps repodeploy-repo/├── base/ # Kustomize 基础清单│ ├── deployment.yaml│ ├── service.yaml│ └── kustomization.yaml├── overlays/│ ├── dev/ # 开发环境覆盖│ │ ├── kustomization.yaml│ │ └── patch-image.yaml│ └── prod/ # 生产环境覆盖│ ├── kustomization.yaml│ └── patch-image.yaml└── .argocd/ # Argo CD Application 定义└── app.yaml这种分离带来三大好处第一开发人员只需关注代码仓库无需触碰 Kubernetes YAML第二运维人员可以在部署仓库中独立管理环境差异和配置变更第三部署历史完全由 Git 版本控制任何变更都可审计、可回滚。实战步骤第一步准备部署清单仓库首先创建 deploy-repo 并编写基础 Kubernetes 清单。以一个简单的 Go Web 服务为例 代码示例# deploy-repo/base/deployment.yamlapiVersion: apps/v1kind: Deploymentmetadata:name: demo-appnamespace: productionlabels:app: demo-appspec:replicas: 3selector:matchLabels:app: demo-apptemplate:metadata:labels:app: demo-appspec:containers:– name: demo-appimage: harbor.stellardata.top/library/demo-app:PLACEHOLDERports:– containerPort: 8080resources:requests:cpu: 100mmemory: 128Milimits:cpu: 500mmemory: 256MireadinessProbe:httpGet:path: /healthzport: 8080initialDelaySeconds: 5periodSeconds: 10其中PLACEHOLDER是占位符CI 流水线在部署阶段会将其替换为实际的镜像 Tag。接下来定义 Kustomize 基础配置和 Argo CD Application 代码示例# deploy-repo/base/kustomization.yamlapiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources:– deployment.yaml– service.yaml—# deploy-repo/.argocd/app.yamlapiVersion: argoproj.io/v1alpha1kind: Applicationmetadata:name: demo-appnamespace: argocdspec:destination:namespace: productionserver: https://kubernetes.default.svcsource:repoURL: https://gitlab.stellardata.top/devops/deploy-repo.gittargetRevision: mainpath: overlays/devsyncPolicy:automated:prune: trueselfHeal: truesyncOptions:– CreateNamespacetruesyncPolicy.automated配置是自动闭环的关键prune: true表示会删除 Git 中已移除的资源selfHeal: true表示当有人手动修改集群资源时 Argo CD 会自动纠正回 Git 中的声明状态。将此 Application 应用到集群 代码示例kubectl apply -f deploy-repo/.argocd/app.yaml -n argocd# 验证 Application 状态kubectl get application demo-app -n argocd# NAME SYNC STATUS HEALTH STATUS# demo-app Synced Healthy第二步配置 CI 流水线的部署阶段GitLab CI 流水线在前几天已经配置了 build 和 test 阶段现在需要新增一个deploy阶段负责将新镜像 Tag 更新到 deploy-repo 中。这是打通 CI 与 CD 的核心环节 代码示例# app-repo/.gitlab-ci.yml 完整流水线stages:– build– test– deployvariables:HARBOR_URL: “harbor.stellardata.top”IMAGE_NAME: “${HARBOR_URL}/library/demo-app”IMAGE_TAG: “${CI_COMMIT_SHORT_SHA}”DEPLOY_REPO: “gitgitlab.stellardata.top:devops/deploy-repo.git”# 构建阶段Kaniko 无守护进程构建build:image:stage: buildimage:name: gcr.io/kaniko-project/executor:latestentrypoint: [“”]script:– /kaniko/executor–context “${CI_PROJECT_DIR}”–dockerfile “${CI_PROJECT_DIR}/Dockerfile”–destination “IMAGE_NAME:{IMAGE\_NAME}:IMAGE_NAME:{IMAGE_TAG}”–destination “${IMAGE_NAME}:latest”–cachetruerules:– if: ‘$CI_COMMIT_BRANCH “main”’# 测试阶段test:unit:stage: testimage: golang:1.22-alpinescript:– go test ./… -v –coverrules:– if: ‘$CI_COMMIT_BRANCH “main”’# 部署阶段更新 GitOps 仓库中的镜像 Tagdeploy:manifest:stage: deployimage: alpine/git:latestbefore_script:– eval $(ssh-agent -s)– echo “$DEPLOY_SSH_KEY” | tr -d ‘r’ | ssh-add –– git config –global user.email “ci-botstellardata.top”– git config –global user.name “GitLab CI Bot”script:– git clone “${DEPLOY_REPO}” /tmp/deploy-repo– cd /tmp/deploy-repo# 替换镜像 Tag– sed -i “s|harbor.stellardata.top/library/demo-app:.*|harbor.stellardata.top/library/demo-app:${IMAGE_TAG}|” overlays/dev/patch-image.yaml– git add -A– “git commit -m “chore: update demo-app image to ${IMAGE_TAG}””– git push origin mainrules:– if: ‘$CI_COMMIT_BRANCH “main”’这里有几个关键点DEPLOY_SSH_KEY是一个预先在 GitLab CI/CD Variables 中配置的 SSH 私钥该密钥对应的公钥需要添加到 deploy-repo 项目的 Deploy Keys 中只读权限即可但 CI Bot 需要 push 权限所以应使用具有写权限的 Deploy Key。IMAGE_TAG使用CI_COMMIT_SHORT_SHAGit 短哈希确保每次提交的镜像 Tag 唯一且可追溯。第三步编写镜像 Tag 更新脚本为了使 Tag 更新更健壮避免sed对多行 YAML 的误伤推荐使用专门的 YAML 处理工具或 Python 脚本。以下是一个基于 Python 的更新脚本它精确修改 Kustomize patch 中的 image 字段 代码示例#!/usr/bin/env python3# update_manifest.py – 更新 GitOps 仓库中的镜像 Tagimport sysimport yamlimport subprocessdef update_image_tag(repo_path, new_tag):patch_file f{repo_path}/overlays/dev/patch-image.yamlwith open(patch_file, ‘r’) as f:docs list(yaml.safe_load_all(f))for doc in docs:if doc and doc.get(‘kind’) ‘Kustomization’:for img in doc.get(‘images’, []):if img.get(‘name’) ‘harbor.stellardata.top/library/demo-app’:img[‘newTag’] new_tagprint(fUpdated image tag to {new_tag})with open(patch_file, ‘w’) as f:yaml.safe_dump_all(docs, f, default_flow_styleFalse)return Trueif __name__ ‘__main__’:repo sys.argv[1] if len(sys.argv) 1 else ‘/tmp/deploy-repo’tag subprocess.check_output([‘printenv’, ‘IMAGE_TAG’]).decode().strip()update_image_tag(repo, tag)对应的 Kustomize overlay patch 文件格式如下脚本会精确修改newTag字段 代码示例# deploy-repo/overlays/dev/patch-image.yamlapiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationimages:– name: harbor.stellardata.top/library/demo-appnewTag: a1b2c3d # CI 自动更新此字段第四步触发 Argo CD 即时同步Argo CD 默认每 3 分钟轮询一次 Git 仓库在生产环境中这个延迟是可以接受的。但如果需要更快的反馈可以配置 GitLab Webhook 推送通知到 Argo CD触发即时同步 代码示例# 获取 Argo CD 的 webhook 端口默认在 argocd-server 上kubectl get svc argocd-server -n argocd# 配置 GitLab 项目的 Webhook# URL: https://argocd.stellardata.top/api/webhook# Content-Type: application/json# Trigger: Push events, branch main# 验证 Argo CD webhook 是否正常curl -X POST https://argocd.stellardata.top/api/webhook-H “Content-Type: application/json”-d ‘{“repository”: {“url”: “https://gitlab.stellardata.top/devops/deploy-repo.git”}}’# 正常返回{}空 JSON 表示接收成功配置 Webhook 后deploy-repo 每次被 CI Bot 推送新提交GitLab 会立即通知 Argo CDArgo CD 在数秒内即可启动同步流程无需等待 3 分钟轮询周期。第五步端到端验证闭环现在来验证完整的闭环。模拟一次代码提交观察全链路行为 代码示例# 1. 开发者修改代码并提交cd app-repoecho “version 1.0.0” src/version.txtgit add -A git commit -m “feat: bump version to 1.0.0”git push origin main# 2. 观察 GitLab CI 流水线执行glab ci view # 或在 GitLab Web UI 查看流水线状态# build:image - test:unit - deploy:manifest 依次通过# 3. 检查 deploy-repo 是否被自动更新cd /tmp/deploy-repo git pullgit log –oneline -3# a1b2c3d chore: update demo-app image to a1b2c3d4# 7e8f9a0 chore: update demo-app image to 7e8f9a0b# 4. 观察 Argo CD 同步事件argocd app get demo-app –refresh# Expected: SYNC STATUS: Synced, HEALTH STATUS: Healthy# 5. 验证集群中的 Pod 已更新kubectl get pods -n production -l appdemo-app# NAME READY STATUS RESTARTS AGE# demo-app-7d6f5c4-x2k9m 1/1 Running 0 45s# demo-app-7d6f5c4-p8n3q 1/1 Running 0 45s# demo-app-7d6f5c4-r1t5w 1/1 Running 0 45skubectl get deployment demo-app -n production -o jsonpath‘{.spec.template.spec.containers[0].image}’# harbor.stellardata.top/library/demo-app:a1b2c3d4从git push到新 Pod 运行全链路在 5 分钟内自动完成无需任何人工干预。这就是 GitOps CI 联动的威力。常见问题问题一CI Bot 推送 deploy-repo 时报权限错误现象deploy:manifest阶段报git push权限被拒绝Permission denied (publickey)。解决确认三点——第一GitLab CI VariableDEPLOY_SSH_KEY使用了正确的 SSH 私钥且变量类型设为File而非Variable这样 GitLab 会将其写入临时文件避免换行符问题第二对应的公钥已添加到 deploy-repo 项目的 Settings → Repository → Deploy Keys并勾选了 “Write access”第三如果使用 HTTPS 方式应使用 Project Access Token 而非个人 SSH Key在.gitlab-ci.yml中通过 CI Job Token 或预配置的 CI/CD Variables 认证。问题二Argo CD 同步后应用状态一直是 Progressing现象Argo CD 显示 SYNC 为 Synced 但 HEALTH 为 Progressing长时间不转为 Healthy。解决通常是 readinessProbe 配置不当或镜像拉取失败。首先检查 Pod 事件kubectl describe pod pod-name -n production确认没有ImagePullBackOff。如果镜像拉取正常检查 readinessProbe 路径是否正确——应用必须实现/healthz端点并返回 HTTP 200。还可以通过kubectl logs pod-name -n production查看应用启动日志确认服务已监听指定端口。问题三GitOps 仓库的 CI Bot 提交过多导致历史膨胀现象每次git push都会在 deploy-repo 产生一条 commit长期运行后 Git 历史极其庞大git clone变慢。解决两种方案。短期方案是定期使用git filter-repo或git gc --aggressive压缩历史。长期方案是采用 Argo CD Image Updaterargocd-image-updater它不再让 CI 直接修改 Git 仓库而是 Argo CD 侧自动监听 Harbor 镜像 Tag 变化并更新 Application 的 image 字段这样 deploy-repo 中只保留人工审批的环境配置变更CI Bot 无需写入权限Git 历史保持干净。总结今天的实战打通了 GitLab CI 与 Argo CD 之间的最后一公里构建了一个完整的从代码提交到集群部署的全自动闭环管道。核心设计要点回顾采用双仓库模型分离应用代码与部署清单CI 的 deploy 阶段自动更新 GitOps 仓库中的镜像 TagArgo CD 的syncPolicy.automated实现声明式自动同步Webhook 将同步延迟从分钟级压缩到秒级。这条管道建立后开发团队只需关注代码质量部署过程完全自动化、可审计、可回滚——这正是 GitOps 理念的最佳实践。不过当前的部署是全量替换式的缺少灰度和回滚的能力。接下来的章节将引入可观测性和渐进式交付来补全这些能力。下期预告明天我们将进入可观测性专题发布第 10 天Prometheus 部署kube-prometheus-stack 与 ServiceMonitor 指标采集为这条全自动管道装上”眼睛”实时监控从构建到部署的全链路健康状态。系列大纲全链路架构总览从代码提交到灰度发布的完整管道设计K8s 集群与网络基础kubeadm 离线部署与 Cilium 网络插件Harbor 私有镜像仓库部署与验证Helm 安装与镜像推送GitLab CE 自托管部署代码仓库与项目管理平台GitLab Runner 配置K8s Executor 与 RBAC 权限设置GitLab CI 流水线搭建.gitlab-ci.yml 与 Kaniko 无守护进程构建Harbor 镜像版本管理与 Tag 策略配置Argo CD 部署与 GitOps 配置仓库创建CI 与 CD 联动从代码提交到部署的全自动闭环今天Prometheus 部署kube-prometheus-stack 与 ServiceMonitor 指标采集Grafana 看板搭建K8s 标准面板与自定义业务看板告警规则与 Alertmanager钉钉/邮件通知渠道配置Argo Rollouts 安装与基础概念CRD 与 Rollout 资源定义金丝雀发布实战setWeight 流量分割与 pause 步骤AnalysisTemplate 指标分析与自动回滚机制全链路端到端演示代码提交→构建→灰度→监控→告警完整流程生产化加固要点Harbor/GitLab/Argo CD 高可用方案供应链安全闭环Trivy 扫描 cosign 签名 Kyverno 验签

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询