LabHub
学习 学习路径 课程

CGOA — GitOps 认证助理

OpenGitOps 四原则 — 为什么是 pull 不是 push

在 LabHub 中继续学习

一句话总结

GitOps 不是部署工具的名称,而是运维模型的名称。只有同时满足 OpenGitOps 定义的四项原则——声明式(Declarative)、版本化且不可变(Versioned and Immutable)、自动拉取(Pulled Automatically)、持续协调(Continuously Reconciled)——才是 GitOps。缺少其中任何一项,都只是“把 YAML 放在 Git 中的 CD pipeline”。

流程图: 运维模型的名称 · 集群的钥匙放在 CI 里 · 无法回答“当前集群中运行着什么” · pipeline 停止时,状态也停止变化

为什么需要它

十年前的部署通常是这样:CI server 完成 build 后,由 CI server 执行 kubectl apply,这叫 push 模型。表面看很简单,却会破坏三件事。

第一,集群的钥匙放在 CI 里。Jenkins 或 GitHub Actions runner 必须持有 kubeconfig 或 ServiceAccount token。而 runner 是执行外部代码的机器,由 fork 提交的一条 PR workflow 可能由此获得 production 部署权限。

第二,无法回答“当前集群中运行着什么”。只能翻查 pipeline 日志,而且有人手动修改的内容连日志也不会记录。

第三,pipeline 停止时,状态也停止变化。push 只在 event 到来时运行。如果凌晨 3 点有人手动修改 replicas,而没有任何事件发生,就无人知晓。

Pull 模型一次颠覆了这三点。运行在集群内部的 agent(Argo CD、Flux)会读取 Git。CI 完全不需要任何集群 credential,它只负责“构建 image 并上传到 registry,再向配置 repository commit 一行 tag”。

工作原理

逐项拆解四个原则如下。

原则 含义 违反后的结果
声明式 描述期望的最终状态,而不是到达状态的步骤 同一 script 运行两次会得到不同结果
版本化且不可变 所有状态都以 commit 留存,已创建的 revision 不再修改 无法回答“从什么时候开始变成这样?”
自动拉取 agent 自行获取获批变更 人员忘记部署时,Git 与现实会分离
持续协调 与事件无关地持续比较并收敛 手动修改会永久保留

考试中经常强调,第三项原则的原文不是“Pushed Automatically”,而是 Pulled Automatically。第四项中的“Continuously”也不是“每次 commit 时”,而是即使没有 commit 也持续运行。Argo CD 默认每 180 秒执行一次该 loop。

“Git 是 SSOT(Single Source of Truth)”也经常被误解。它不是说“所有文件都在 Git 中”,而是声明:“当集群与 Git 不一致时,Git 才是正确状态。” 关键在于方向已经确定。发现 drift 后反过来修改 Git 以匹配集群,不是 GitOps,只是事后补文档。

声明式也并非总是占优。顺序本身至关重要的任务——database schema migration、one-time data correction、certificate initial issuance——无法仅用“最终状态”表达。因此,Argo CD 提供 hook(PreSync/PostSync)作为 imperative escape hatch。准确的理解是:声明式是默认值,命令式是明确标注的例外。

现场会遇到的情况

作者的 7 节点家庭实验室完整采用该模型。Gitea 位于 10.0.0.200,Argo CD 位于 10.0.0.201,Harbor 位于 10.0.0.202,Grafana 位于 10.0.0.203——都来自 MetalLB L2 pool 10.0.0.200-215。网络由不使用 kube-proxy 的 Cilium 1.20 eBPF 处理,上层运行 kube-prometheus-stack 与 CloudNativePG。整个 stack 并不是从集群外 push 进去,而是由内部 pull 得到。

有一次事件同时展示了声明式的威力与边界。该集群的 controlPlaneEndpoint 不是 VIP 或 DNS,而被固定为第一台 control plane 的物理 IP 10.0.0.120。后来即使把 control plane 扩展到三台、拥有三个 etcd member,只要第一台节点故障,kubectl 与 7 台 kubelet 仍会全部无法连接。因为 apiserver certificate SAN 中没有其他节点 IP,TLS validation 从一开始就会失败。

这与 GitOps 的关系在于,它说明:没有写入声明文件的值就不受管理controlPlaneEndpoint 在创建集群的瞬间确定一次,之后既不在 Git 中,也不属于 reconciliation 对象,因此修改起来极其痛苦。在实际工作中,区分 GitOps 能够管理的区域,与 cluster bootstrap 等外部区域,比单纯使用工具更重要。

接下来阅读什么

下一篇 reading 会准确定义 desired state、drift、reconciliation、convergence 等考试术语。之后的模块会在 /root/cgoa-repo/ 下创建真实 GitOps repository 骨架,并通过 kubectl kustomize 亲眼确认各环境的渲染结果如何不同。