从流水线推机器到 GitOps
上一篇 CI/CD 讲的流水线,工作方式是:构建出镜像后,由流水线主动去「推」到目标环境——调 kubectl apply、调云 API。这种方式有个隐藏问题:集群里实际跑的版本,和 Git 仓库里写的版本,之间没有任何强制对应关系。有人在生产上手动 kubectl edit 改了个东西,Git 里完全看不出来,时间一长两边就漂移了。
GitOps 换了个方向:不再让流水线去推集群,而是让集群自己盯着 Git 仓库里那份声明,把自己对齐过去。你要改生产,就改 Git 仓库并合并——剩下的交给集群里的同步组件。Git 仓库因此变成了「唯一事实来源」:想知道生产跑的是什么,看仓库就够了。
传统流水线是「我推给你」;GitOps 是「仓库里写着应该是什么样,集群自己去对齐」。
- 声明式你只在 Git 里写「要什么」,同步组件负责把它在集群里实现。
- 唯一事实来源集群现状和 Git 仓库始终对齐,漂移会被立刻发现。
- Argo CD最主流的 GitOps 工具之一,盯着仓库、把集群拉齐。
- 回滚即回退 Git生产出问题,把仓库版本回退一下就行。
声明式交付:Git 是唯一事实来源
GitOps 说的「声明式」,和 Terraform、Kubernetes 是同一个思路:你不写动作,只写期望。在 GitOps 里,这份期望就是放在 Git 仓库里的一堆 YAML——哪个服务跑什么镜像版本、副本数多少、暴露什么端口。
它和传统流水线最大的区别是方向反过来了:流水线时代是「构建产物 → 推送集群」,集群是被动的;GitOps 时代是「仓库声明 → 集群主动拉取对齐」,集群里有个组件一直在监听仓库。这么换来的好处很实在:任何一次环境变更,Git 历史里都能查到——谁、什么时候、把哪个镜像版本合进去的。想知道生产为什么是这个样子,git log 一翻就清楚了。
另一个好处是权限收敛:开发和发布人员不需要再持有生产集群的直接操作权限,他们能做的就是改仓库、提合并请求。真要对生产动手,得走代码评审——权限收紧的同时,审计链反而完整了。
Argo CD:让集群对齐仓库
Argo CD 是 Kubernetes 上用得最多的 GitOps 工具。它在集群里跑一个组件,持续盯着你指定的 Git 仓库路径,发现仓库里的声明和集群现状不一致,就把它对齐过去:
# 一个最小的 Argo CD 应用定义
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: web-prod
spec:
project: default
source:
repoURL: https://git.example.com/platform/manifests.git
path: overlays/prod
targetRevision: main
destination:
server: https://kubernetes.default.svc
namespace: web
syncPolicy:
automated:
prune: true
selfHeal: true
几个关键字段:repoURL + path 告诉 Argo CD 去哪个仓库的哪个目录读声明;destination 是对齐到哪个集群哪个命名空间;automated 表示发现漂移就自动同步回来。selfHeal: true 尤其关键——有人手动在集群里改了东西,Argo CD 发现和仓库不一致,会自动把它改回仓库里的样子,手工漂移从此无处遁形。
多环境:一份配置,多套叠加
测试、预发、生产三个环境跑的是同一套服务,只是副本数、资源规格、副本数不同。GitOps 的做法和 Kustomize 天然契合:一份 base 声明,每个环境一个 overlay 叠加差异:
manifests/
├── base/
│ ├── deployment.yaml # 服务名、镜像、基础配置
│ └── service.yaml
└── overlays/
├── dev/ # 副本数 1、小规格
├── staging/ # 副本数 2、中规格
└── prod/ # 副本数 3、大规格、开 HPA
Argo CD 里就配三个 Application,分别指向 overlays/dev、overlays/staging、overlays/prod。服务本身的定义只写一份,环境差异全部在 overlay 里。想从预发推到生产,就是把同一份镜像版本号在 prod overlay 里改一下——全程走 Git 评审,没有任何一步是直接对生产集群动手。
自动同步与人工把关
Argo CD 可以全自动同步(合并进仓库就立刻生效),也可以只做差异提醒、人工点确认再同步。生产环境的务实做法通常是:测试环境全自动,生产环境半自动——仓库一变 Argo CD 就标出「现在集群和仓库差了这些」,由值班同学在面板上确认后再点同步。
为什么不全自动?因为 Git 评审通过 ≠ 这次发布一定安全。合并了一个坏版本,自动同步会立刻把它送到生产。留一道人工确认,等于在流水线最后加了双保险:代码评审保证改动是对的,人工同步确认保证时机是对的。配合上一篇讲的金丝雀发布,先小流量验证、再全量,生产变更就稳得多。
回滚:回到 Git 的某个版本
GitOps 最香的时刻就是回滚。传统模式下回滚,要重新构建老版本镜像、再走一遍发布流水线;在 GitOps 里,回滚就是一次 git 操作:
# 找到出问题那次合并之前的提交
git log --oneline overlays/prod
# 把 prod overlay 里的镜像版本指回上一个稳定版本
# 提交并合并,Argo CD 自动把生产对齐回旧版本
因为集群永远在盯着仓库,你把仓库改回去,它就自动把生产改回去。回滚从「重新发布一次老版本」变成「撤销一次提交」,分钟级完成,而且全程有 Git 记录。这也是为什么 GitOps 团队特别强调:所有环境变更都必须走仓库——只要走了仓库,回滚就永远是简单的;只要绕过仓库直接改集群,就又掉回了「凭记忆回滚」的老路。
落地一份最小 GitOps 仓库
对一个还没用过 GitOps 的团队,别上来就把全公司环境都纳管。推荐这个最小起步路径:
第一周:挑一个无状态小服务
- 把它的 K8s 声明放进 manifests 仓库
- 给测试环境接 Argo CD,先跑全自动同步
第二周:加上 overlay 多环境
- 拆 base + overlays/dev + overlays/staging
第三周:上生产,改半自动
- prod 环境保留人工同步确认
- 演练一次「出问题就 git revert」的回滚
几个新人最容易踩的坑提前记好:第一,别让人再拿 kubectl 直接改生产——改了 Argo CD 会给你改回来,两边打架。第二,敏感信息(数据库密码)不要明文写进仓库,用专门的密钥管理(如 sealed-secrets)或外部密钥系统注入。第三,先接测试环境,把「仓库改完环境自动跟着变」这件事跑顺,再碰生产。
说到底,GitOps 不只是换个发布工具,它是把「环境长什么样」这件事,从一堆人手头的零散操作,收敛成一份有版本、有评审、随时可回滚的代码。当你想知道「生产现在到底跑的是什么」,答案不再是翻监控面板猜,而是直接打开那个仓库——这就是它最大的安心感。