10.2 GitOps:持续协调、发布与回滚
传统流水线常在最后执行 kubectl apply:CI 拿到集群凭据,向生产环境推送一次变更。GitOps 把方向反过来:集群内的控制器读取被批准的期望状态,持续比较 live state,并把差异收敛回去。
CI:源代码 → 测试 → 构建不可变制品 → 签名/扫描
CD:期望状态仓库或 OCI artifact → 协调器 → 集群GitOps 不是“所有 YAML 都放进 Git”,关键是声明式状态、版本化来源、自动拉取和持续协调构成控制回路。
Git 不一定直接存放源码生成物
一条可追溯发布链应固定不可变身份:
source commit
→ image: registry.example/atlas@sha256:...
→ deployment manifest commit / signed OCI artifact
→ reconciler observed revision
→ running Pod imageID环境配置中应使用 image digest,或由自动化把经过验证的 digest 更新进仓库。只写 :latest 会让同一个 Git commit 在不同时间解析成不同二进制,回滚和审计都会失真。
配置来源可以是 Git,也可以是受支持的 OCI artifact 或 Helm repository。重要的不是介质名字,而是来源可验证、版本不可含糊、变更可审批。
协调循环不是一次部署
以 Argo CD 为例,Application 描述来源、目标和同步策略:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: atlas-api
namespace: argocd
spec:
project: production
source:
repoURL: https://git.example.com/platform/env-config.git
targetRevision: 7f3c91e
path: clusters/prod/atlas-api
destination:
server: https://kubernetes.default.svc
namespace: atlas-prod
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- PruneLast=trueselfHeal 允许控制器修复 live state 的手工漂移;prune 允许删除来源中已经不存在的对象。两者都改变故障模式:错误提交可能被迅速放大到全集群,所以生产环境要配项目边界、同步窗口、健康检查和关键资源删除确认。
自动同步开启时,不要把“点击旧版本回滚”当成长期方案:如果 Git 仍声明新版本,协调器还会再次把它部署回来。可靠回滚应产生一个新的、可审计的期望状态变更,例如 revert 配置提交或把 digest 提升回已知良好版本。
仓库边界映射权限与发布节奏
一种常见布局:
env-config/
├── apps/
│ └── atlas-api/base/
└── clusters/
├── staging/atlas-api/
└── prod/atlas-api/应用团队维护 base 和应用参数,平台团队维护集群能力与策略,生产环境变更由独立 CODEOWNERS 审批。不要复制整套 YAML 形成三个逐渐分叉的环境;用 Kustomize overlays、Helm values 或其他明确的组合方式,只表达必要差异。
仓库也不应大到任何一个提交都触发所有集群重算。按权限、故障半径和变化频率划分,比追求形式上的 mono-repo 或 multi-repo 更重要。
Promotion 是提升同一个制品
正确的环境晋级不是在 staging 和 prod 各构建一次:
构建一次 image digest D
→ staging 引用 D
→ 集成、性能与策略验证
→ PR 将 prod 引用更新为同一个 D
→ 分批发布与业务验证这样生产问题可以追溯到同一个已测试制品。环境专属配置应与制品身份分离,数据库迁移还要明确向前兼容、执行顺序和失败恢复,不能假设回滚镜像就能回滚数据。
Secret 不能以明文进入期望状态
Git 可以保存“需要哪个秘密”的声明,但不应保存秘密本身。常见方案包括:
- External Secrets 一类控制器从云 Secret Manager 或 Vault 拉取;
- SOPS 加密清单,密钥放在 KMS,协调器只在受控环境解密;
- CSI driver 把秘密挂载到工作负载,减少 Kubernetes Secret 的复制范围。
Base64 只是编码。即使使用加密文件,也要限制解密身份、轮换密钥、避免秘密出现在 diff、日志和渲染后的 artifact 中。
Break-glass 必须设计回归路径
事故中可能需要暂停协调或直接修补 live state。成熟流程会预先定义:
- 谁能暂停哪个应用,凭据多长时间过期;
- 何时记录工单、命令和影响范围;
- 服务恢复后,如何把有效修复提交回期望状态;
- 如何恢复协调并验证没有二次回滚。
没有回归路径的 kubectl edit 会成为下一次事故的种子;完全禁止紧急操作又会拖慢恢复。GitOps 的目标是让例外可控、短暂、可追溯。
上线前的控制面检查
- 来源是否固定到可追溯 revision 或 digest?
- 协调器是否只能写入授权 namespace 和资源类型?
prune、selfHeal、删除确认和同步窗口是否匹配风险?- CRD 与其实例、数据库迁移与应用版本是否有顺序约束?
- 控制器自身故障时,当前工作负载是否继续运行?
- 能否从 Git revision 定位到运行中的 image ID?
- 紧急暂停、回滚和恢复协调是否演练过?
IaC 与 GitOps 都使用声明式配置,但所有权不同:前者通常管理云资源和集群底座,后者持续管理集群内期望状态。让两个控制器同时改同一字段,最终得到的不是“双保险”,而是永不停止的争夺。
参考资料
- OpenGitOps, GitOps Principles
- Argo CD, Automated Sync Policy
- Argo CD, Sync Options
- Flux, Core Concepts