GitOps 是什么
这一课你将能做到
- 用自己的话对比 Push(CI 推集群) 与 Pull(控制器拉 Git) 两种部署模型,指出各自凭据持有方与漂移风险
- 背出 OpenGitOps 四原则(声明式、版本化与不可变、自动拉取、持续调和),并能逐条对应到 Argo CD/Flux 的具体行为
- 画出「Git 存 Chart/values → 控制器调和 → 集群逼近期望状态」的闭环,说明为什么「回滚 = git revert」
为什么要学
Helm 解决了「怎么打包、怎么参数化」;但如果部署仍由 CI 持有高权限 kubeconfig 执行 helm upgrade,你会遇到三类老问题:凭据散落在流水线里越积越多、有人手改集群后没人能发现、回滚靠「谁记得当时怎么部署的」。GitOps 换了一个思路:把 Git 仓库当作集群期望状态的 唯一事实源(single source of truth)——所有变更走 PR 评审,集群内(或可信位置)的控制器 持续对比 live 状态与期望状态,发现差异就同步或告警。OpenGitOps 社区把这套原则总结为四条,是可以直接背进面试的标准答案。本课先建立概念图像,仓库布局与 Argo/Flux 实操在后续三课落地。
先建立图像
Push 模式(传统 CI 部署)
开发者 merge → CI 构建镜像 → CI 持 kubeconfig
→ kubectl apply / helm upgrade 「推」进集群
痛点:CI 权限越滚越大;集群被手改后无告警;真相散落在流水线日志
Pull 模式(GitOps)
Git 仓库:charts/ + env/*/values.yaml + Application/HelmRelease 声明
↑ 一切变更走 PR 评审
集群内 Argo CD / Flux 按 interval 或 webhook 拉取、对比、sync
→ 等价于受控的 helm upgrade / kubectl apply
优势:审计=git log;回滚=git revert;CI 可以完全不持集群凭据
| 维度 | Push(CI 推) | Pull(GitOps) |
|---|
| 真相源 | CI 脚本 + 人工记忆 | Git 仓库声明 |
| 改集群凭据 | CI 持 kubeconfig | 控制器在集群内用自身 ServiceAccount |
| 漂移 | 难以自动发现 | selfHeal / reconcile 自动纠正或告警 |
| 回滚 | 重跑旧流水线或手搓 | git revert 后控制器自动对齐 |
| 变更评审 | 常缺 | PR diff 即评审记录 |
人话:Push 像快递员拿着你家钥匙进门摆货,快递公司换人你不知道;Pull 像你家贴了一张购物清单,店员每天对照清单自己补货——钥匙始终留在你家里。
跟着做
步骤 1:诊断你当前的部署属于哪一类
回忆或打开团队流水线,找两个证据:
- 有没有一步
kubectl apply / helm upgrade 跑在 CI 里、且 CI 存有 kubeconfig/密钥?→ Push 痕迹
- 集群里有没有 Argo CD(
argocd 命名空间)或 Flux(flux-system 命名空间)的 Pod?Application/HelmRelease 是否指向某个 Git path?→ Pull 痕迹
笔记写一行:「我们现在是 ____ 为主。」没有对错,先认清现状。
步骤 2:对照 OpenGitOps 四原则并翻译成人话
打开 OpenGitOps 官网,把四条原则用自己的话写进笔记:
- 声明式(Declarative):期望状态必须是声明式描述——不是「执行这些命令」,而是「系统应该长这样」
版本化与不可变(Versioned & Immutable):期望状态存在 Git 里,任何变更都是新 commit,历史不可篡改自动拉取(Pulled Automatically):由集群侧代理自动拉取期望状态,而不是外部脚本推进去持续调和(Continuously Reconciled):代理不断对比 live 与 desired,把 live 拉向 desired——不是「部署一次就完事」步骤 3:画出本站目标布局草图
repo/
deploy/
charts/backend/ ← 业务 Chart(前面六课的产物)
env/dev/backend-values.yaml
env/prod/backend-values.yaml
argocd/applications/backend-dev.yaml ← 控制器声明(或 Flux 的 HelmRelease)
在草图上标三个箭头并写注释:CI 只负责测试与推镜像(不打集群);改集群期望 = 改 Git(PR);同步 = 控制器的事(没人手动 apply)。
步骤 4:列举「漂移(drift)」的具体例子
写下三个会让 live ≠ desired 的真实动作,并标注 GitOps 下会发生什么:
- 有人
kubectl scale deploy backend --replicas=5 救火 → selfHeal 开启时被拉回 values 的副本数
- 有人在云控制台改了镜像 tag → 下次 reconcile 被纠正,或 UI 长期显示 OutOfSync
- 有人手改了 Service 端口 → 与 Git 期望产生 diff,评审时一眼可见
结论一句:「漂移不可怕,可怕的是不可见。」GitOps 把手改变成 可见的告警或自动纠正。
步骤 5:划清 Helm 与 GitOps 的边界(填空)
标准答案应接近:Helm 解决「如何描述与渲染期望状态」(打包、模板、参数化);GitOps 解决「谁、何时、以什么版本把期望状态落到集群,以及如何持续保持一致」(操作模型)。所以 GitOps 可以同步裸 YAML/Kustomize/Helm,本站选 Helm 是因为多环境参数化需求与生态。
步骤 6:口头验收
一分钟说清:「我们 backend 的 Chart 在 Git 里,dev/prod 各一份 values;改镜像 tag 走 PR;Argo CD 拉到变更后自动 sync;有人手改集群会被 selfHeal 拉回;回滚就是 revert 那个 PR。」
讲清楚要点
- 因为期望状态应可评审,所以改集群配置走 Git PR 而不是直连生产 kubectl——技术讨论发生在 diff 上,环境差异一目了然,变更历史即部署历史。
- 因为 CI 持高权 kubeconfig 会放大攻击面,所以 GitOps 把「改集群」收敛到集群内控制器——CI 只需要推镜像的 registry 凭据;即使 CI 被攻破,攻击者也拿不到集群钥匙。
- 因为手改会造成漂移,所以控制器必须持续 reconcile——这是「状态机」思维:没有一次性的部署,只有不断向期望状态收敛的过程。
- 因为回滚要可审计,所以优先 git revert,而不是只在集群里 helm rollback——只 rollback 集群不改 Git,下一轮 sync 又把新版本推回去,真相分裂。
- 因为 Helm 与 GitOps 正交,所以本站组合使用——Helm 出 Chart 与 values,GitOps 管触发与调和;二者解耦后可各自演进。
- 因为工具有 Argo CD 与 Flux 两家主流,所以先吃透共同原则再选型——四原则是纲,工具只是纲的实现;下一课仓库布局,再后面分别入门。
你可能会懵的地方
-
GitOps 之后还需要 CI 吗?
需要。CI 负责测试、构建镜像、推送 registry、甚至自动开 PR 改 values(Image Automation 思路);它只是不再持有「apply 到集群」的职责与凭据。GitOps 重定义的是 CD 的最后一步,不是消灭 CI。
-
紧急事故时还能 kubectl 救火吗?
偶发可以,但要形成纪律:救火动作事后必须回写 Git(或接受 selfHeal 拉回并重新走 PR)。规范上 Git 永远是真相源,绕过 Git 的改动默认视为临时态。
-
Pull 模式就没有凭据风险了吗?
风险被重新分配而不是消失:Git 写权限、PR 合并规则、控制器自身的 RBAC、仓库访问凭证成为新的攻击面。所以 GitOps 落地必然配套分支保护、CODEOWNERS、最小权限。
-
GitOps 和 Infrastructure as Code(Terraform)什么关系?
IaC 强调用代码描述基础设施;GitOps 是一套 操作模型(谁拉取、怎么调和、真相在哪),常见载体是 K8s 清单,但 Terraform 状态也可以 GitOps 化。本 track 聚焦 K8s 应用清单与 Helm。
-
数据库 schema 变更也走 GitOps 吗?
代码层面的迁移脚本随镜像发布;但执行时机(如 Flyway 启动迁移)要设计好与滚动更新的顺序。这类「有状态、不可逆」操作是 GitOps 的边界难点,面试能点到「谨慎处理有状态变更」即可。
错法对照
| 错法 | 问题 | 正解 |
|---|
| CI 一把梭 helm upgrade 到生产 | 高权凭据、难审计 | Git 存期望 + 控制器 sync |
| 改了集群不改 Git | 下轮 sync 被覆盖或长期漂移 | 改 values 走 PR |
| 以为 GitOps = 必须用某个品牌工具 | 选型焦虑、概念混乱 | 先背四原则,再选 Argo/Flux |
| 无 PR 直接 push main 改 prod values | 生产无评审 | 分支保护 + CODEOWNERS |
| 回滚只做 helm rollback 不改 Git | 真相分裂,下轮又被推回 | git revert 并让控制器对齐 |
| 把 GitOps 理解成「Git 备份 YAML」 | 缺了调和与自动拉取两环 | 补齐「持续对比+收敛」的认知 |
卡点急救
- 团队觉得 GitOps「多一道 PR 手续,太慢」——用数据回应:PR 评审通常分钟级,而一次「手改集群导致配置漂移」的排障平均小时级;可以先在 dev 环境全自动(automated sync)、prod 保 PR 评审,速度与安全分环境平衡。
- 历史遗留配置散落在 CI 变量、本地脚本、文档里——不必一次迁完:先把 backend 一个应用搬进 Git(Chart+values+Application),跑稳一个季度,再按同构模板复制到其他服务;「先加后迁,不砸现网路径」。
- 有人担心「控制器权限太大」——对齐事实:控制器权限=它管理的命名空间范围(可用 Argo 项目/AppProject 或 Flux 的 RBAC 收窄),而 CI 的 kubeconfig 通常是全集群权限;迁移后攻击面是缩小而非扩大。
面试常问
-
什么是 GitOps?核心原则有哪些?
GitOps 是一种持续交付操作模型:以 Git 为期望状态的唯一事实源,所有变更通过 PR 版本化,由集群侧控制器自动拉取期望状态,并持续调和(对比 live 与 desired、把 live 收敛到 desired)。OpenGitOps 四原则:声明式、版本化与不可变、自动拉取、持续调和。
-
GitOps 与传统 CI/CD(Push 模式)的本质区别?
推/拉之别与凭据归属:Push 由 CI 持 kubeconfig 主动推进集群,CI 是「部署执行者」;Pull 由集群内控制器主动从 Git 拉取,CI 退为「构建者」。由此带来三个差异:漂移可自动纠正(reconcile 是持续行为而非一次性动作)、回滚等价于 git revert、集群凭据不再散落在流水线。
-
为什么 GitOps 常与 Helm 一起用?
Helm 负责「表达期望状态」:Chart 提供可复用的模板结构,values 提供环境参数化,第三方组件生态也以 Chart 分发;GitOps 负责让这些期望状态持续生效。控制器(Argo CD/Flux)原生支持 Helm 渲染,二者组合 = 可评审的参数化交付。
自测三问
- Push 与 Pull 模型里,「改集群的凭据」分别由谁持有?这带来什么安全差异?
- 说出 OpenGitOps 四原则,并各用一句话解释。
- 「git revert 一个 PR」和「helm rollback 一个 revision」分别改变什么?为什么 GitOps 要求两者最终一致?
小结一句话
GitOps 用 Git 声明期望状态,由集群侧控制器持续拉取并调和;与 Helm 组合后,多环境 values 的每次变更都可评审、可回滚、可审计——这是后面 Argo CD 与 Flux 实操的共同地基。
延伸