← 全部案例
01CI/CD · GitOps

GitOps 持续交付流水线

代码合并后自动测试、构建、发布到 Kubernetes。坏版本被就绪探针拦住,旧版本持续服务,一次 git revert 就能回滚。

笔记本 VirtualBox + Vagrant,3–4 台 Ubuntu 22.04 虚拟机

背景与目标

一个 Go 编写的 Web 应用,原来靠手工 docker build 和 kubectl apply 发布:步骤多、容易漏,出了问题也说不清线上跑的到底是哪个版本。

目标:每次发布都能追溯到具体的代码提交;发布失败不影响用户;回滚不靠登录服务器,而是一个可审计的操作。

架构

代码检查
  1. 提交 PR
  2. GitHub Actionsgo vet · go test
  3. 合并 main分支保护
构建
  1. Jenkins Pipeline轮询代码仓库
  2. docker build构建时再跑测试
  3. 私有 Registrytag:构建号-提交号
部署
  1. 更新 GitOps 仓库只改镜像 tag
  2. Argo CDauto-sync · selfHeal
  3. Kubernetes滚动更新

关键做法

  1. 01

    代码与部署配置分仓

    应用代码放在 labapp,"线上应该是什么样"放在 labapp-gitops。部署历史就是 Git 历史,谁在什么时候改了什么一目了然。

  2. 02

    PR 阶段自动检查

    GitHub Actions 在 PR 上跑 go vet 和单元测试,配合分支保护,检查不过不能合并。为了能测,先把路由抽成独立函数并补上测试。

  3. 03

    Jenkins 构建并推送镜像

    自建带 Docker CLI 的 Jenkins 镜像;镜像 tag 采用"构建号-提交号 7 位",从任意一个线上镜像都能反查到对应的代码提交。

  4. 04

    最小权限更新部署仓库

    Jenkins 使用 fine-grained token,只能写 labapp-gitops 一个仓库,每次只改镜像 tag 一行;Jenkins 本身不持有集群凭据。

  5. 05

    Argo CD 自动同步

    开启自动同步、prune 和 selfHeal:有人手动改了集群,也会被改回 Git 里的状态,线上与配置始终一致。

  6. 06

    坏版本演练

    故意发布一个监听端口写错的版本:单元测试发现不了,但就绪探针失败,新 Pod 始终不 Ready;maxUnavailable 设为 0,旧 Pod 不会被删除,服务不中断。在部署仓库 git revert 后自动恢复。

遇到的问题

Argo CD 的 Redis 一直拉不下镜像

原因
chart 默认镜像来自 ECR Public,国内网络访问失败
解决
在 values 中改用 docker.io 镜像,并固定 chart 版本

检查失败的 PR 仍然可以合并

原因
首次配置分支保护时检查还没运行过,没勾上;管理员默认可绕过规则
解决
补选必需检查,并开启"不允许绕过规则"

节点拉私有镜像时报 HTTP / HTTPS 不匹配

原因
containerd 的 hosts.toml 多写了 skip_verify,被当作 TLS 配置,优先走 HTTPS
解决
删除该配置,通过 containerd 日志确认按 HTTP 拉取

两个节点关机后,上面的 Pod 一直显示 Running

原因
3 个节点挂了 2 个,节点控制器判定为大面积故障,小集群会停止驱逐
解决
cordon 故障节点并强制删除其上的 Pod,由控制器在健康节点重建

结果

  • 从合并代码到新版本上线全程自动,无需登录服务器
  • 每个线上镜像都能对应到一个 Git 提交
  • 坏版本被就绪探针拦截,旧版本持续服务,用户无感知
  • 回滚就是一次 git revert,几分钟内完成且有记录可查