TT Lab
开始
学习 学习路径 课程

CGOA — GitOps 认证助理

GitOps 与什么不同、立于什么之上 — 相关实践与模式

在 TT Lab 中继续学习

一句话总结

IaC、CaC 只做到“把状态写成文件”,CI/CD 是“按预先设定的触发器实现自动化”,而 GitOps 是在此之上,再加上代理自己获取(pull)、每当出现偏差就对齐(reconcile)的部分。模式就是对这个调谐循环放在哪里、何时唤醒它所做的选择。

为什么需要它

CGOA 的 Related Practices 领域(16%)要求把 GitOps 与相邻概念区分开。在实际工作中经常听到“我们把 Terraform 放在 Git 里,所以是 GitOps”“Jenkins 执行 kubectl apply,所以是 GitOps”,对照 OpenGitOps 原则,这两种说法都只对了一半。因为缺少了原则 3(Pulled Automatically)和原则 4(Continuously Reconciled)。只有准确了解边界,才能说清楚还要补上什么才算 GitOps。

Patterns 领域(20%)是接下来的问题:调谐器(reconciler)放在集群内还是集群外,定期拉取还是用事件唤醒,如何把渐进式交付放进 GitOps 循环,状态仓库是否只用 Git。每种选择在官方文档中都有其理由。

工作原理

相关实践——按 CNCF 术语表的定义来区分

实践 CNCF 术语表的定义 与 GitOps 的关系
IaC 把基础设施定义存为文件,取代手动 provisioning。单一事实来源,通过 CI/CD 流水线管理 满足原则 1、2(声明式,版本化且不可变)。原则 3、4 视工具而定,可能有也可能没有
CaC 像代码一样对配置做版本管理。opengitops.dev 上引用的 Kelsey Hightower 的话“GitOps 是继 configuration as code 之后最好的东西”概括了这种关系 仓库相同,但 GitOps 把应用的执行主体从人、流水线换成了代理
DevOps 从开发到运维由一个团队拥有全过程。减少交接的文化与流程变革 GitOps 是落实这种文化的运维方式之一
DevSecOps 把安全责任并入 DevOps。通过自动化的 CI/CD 工作流和策略执行,在不阻碍开发者的前提下强制落实安全 Git 的评审与审计历史,以及调谐器的最小权限,就是落实该策略执行的位置
CI 尽可能频繁地集成代码变更。从提交开始,到经过测试的制品结束 GitOps 并不取代 CI。引用 CI 所生成制品的声明,就是 GitOps 的输入
CD 把变更自动部署到验收环境(continuous deployment 则是生产环境)。包含测试和回滚流程 传统 CD 由触发器推送(push),GitOps 由代理拉取(pull)

OpenGitOps 术语表这样说明 pull:代理必须能够不仅在有变更时,而是随时访问状态仓库中的期望状态(desired state),这样才能实现原则 4 的持续调谐。传统 CI/CD 按“预先设定的触发器”运行自动化,而 GitOps 的调谐每当出现偏差(divergence)就会发生,偏差不仅出现在有意发布新版本时,也出现在实际状态无意中漂移(drift)时。反馈(feedback)一词来自控制理论中的闭环,指先前的应用尝试对实际状态产生了什么影响,代理会据此进行重试、回滚或告警。

模式 1——pull 周期与基于事件的调谐

两种调谐器默认都是周期性 pull。Argo CD 每 3 分钟轮询一次 Git、OCI、Helm 仓库,Flux 的 Kustomization 每 5 分钟(.spec.interval)调谐一次。为消除这种延迟,两者都会接收 Webhook。Argo CD 通过 API 服务器的 /api/webhook 接收 GitHub、GitLab、Bitbucket、Azure DevOps 等的 push 事件,Flux 则由 notification-controller 的 Receiver(端口 9292)接收 GitHub、GitLab、Harbor、Jenkins 等的事件,让“pull 管道像 push 一样灵敏”。

重要的是,Webhook 不会破坏原则 3。Argo CD 文档写道,不信任 Webhook 负载,即使收到未经认证的事件,所做的也只是每 3 分钟本来就会发生的 refresh。事件只是“现在就去拉取”的信号,并不推送状态。基于事件的调谐不是取代 pull,而是把 pull 的时间点提前。

模式 2——调谐器在集群内还是集群外

in-cluster 调谐器调谐自己所在的集群。Argo CD 的 destination.server: https://kubernetes.default.svc 就是这样,Flux 通过 bootstrap 用同样的方式把自己也管理起来。external 调谐器在一个地方调谐多个集群。Argo CD 把目标集群的凭据注册为带有 argocd.argoproj.io/secret-type: cluster 标签的 Secret(name、server、config),并可以用 namespaces 缩小访问范围。Flux 文档也写道“可以用一个集群管理同一集群或其他集群中的应用”。区别在于凭据汇集在哪里:in-cluster 是每个集群只持有自己的凭据,external 是管理集群持有所有集群的凭据。

模式 3——把渐进式交付放进循环

Flux 术语表把渐进式交付(progressive delivery)定义为“先把新功能发给一部分用户并观察、调整,再部署给全部用户”,并列举金丝雀(Canary)、A/B、功能开关(feature flag)等技术。在 Flux 中由名为 Flagger 的独立控制器负责,在 Argo 中则由 Argo Rollouts 负责。Argo Rollouts 用 Rollout 资源代替 Deployment 来管理 ReplicaSet,spec.template 改变时,按 strategy(blue-green、canary)推进,通过指标分析后,把新的 ReplicaSet 标记为 stable。从 GitOps 的角度,关键在于部署策略本身就是声明(desired state)的一部分。Git 中会同时写下“新镜像”和“每次增加 10%,同时观察错误率”,调谐器则按该声明慢慢对齐。

模式 4——状态仓库用什么

OpenGitOps 术语表把状态仓库(state store)定义为“存储不可变版本的期望状态,并提供访问控制和审计的系统”,指出 Git 是名称的由来和代表性例子,但满足条件的其他系统也可以。Flux 用 OCIRepository 和 OCI 制品实现了“Gitless GitOps”。用户仍然用 Git 管理状态,但控制器只看容器注册表,所以 Git 服务器不再是运行时依赖。Argo CD 同样接受 Kustomize、Helm、OCI 镜像、YAML 目录、插件作为来源。反过来,Argo CD 的 --local 清单上传,是文档自己称为“GitOps 反模式”的开发用功能。

在现场相遇的样子

一个团队原来用 Jenkins 通过 kubectl apply 部署,接入 Argo CD 时保留了 Jenkins 的 apply 步骤。结果两个主体对同一个资源互相回滚,Argo CD 一直报告 OutOfSync。把 CI 的职责缩减为“构建镜像并修改 Git 中的标签”之后,问题就消失了。这是不划定 CI 与 GitOps 边界时出现的典型案例。

渐进式交付中,自动回滚会把流量和 ReplicaSet 恢复原状,但容易忽略 Git 中的声明并没有变。调谐器仍然把新镜像视为期望状态,所以在有人把 Git 回滚之前,同样的尝试可能反复发生。需要一套以 Git 提交来收尾的回滚流程。

接下来的理论要看什么

接下来的理论将直接对比实现这些模式的两种工具 Argo CD 与 Flux 的结构,并看通知、可观测性、CI 集成分别接在哪里。参考:OpenGitOps Principles、GitOps Glossary、CNCF Glossary — GitOps、Argo CD Webhook Configuration、Flux Core Concepts、Flux Webhook Receivers。