写点什么

GitOps 的 12 个痛点

作者:俞凡
  • 2022 年 4 月 16 日
  • 本文字数:5828 字

    阅读完需:约 19 分钟

如今很多团队采用 GitOps 作为标准部署流程,这篇文章总结了 GitOps 的 12 个痛点,从而帮助我们在采用这一实践的过程中更好的理解 GitOps 的优势和缺陷,选择适合自己的解决方案。原文:The pains of GitOps 1.0[1]


GitOps 作为软件发布实践有很多优点,但就像其他解决方案一样,它也有缺点,当我们从采用 GitOps 的狂热中冷静下来后,也需要讨论一下 GitOps 的问题了(以及现代 GitOps 工具)。


在本文中,我们将讨论 GitOps 的 12 个痛点:

  1. GitOps 只覆盖软件生命周期的一个子集

  2. 用 GitOps 分割 CI 和 CD 并不容易

  3. GitOps 无法将发布部署到不同的环境中

  4. 对于多环境配置建模没有标准实践

  5. 自动扩容和动态资源管理破坏 GitOps

  6. 对于回滚没有最佳实践

  7. GitOps(和 Git)的可观察性不成熟

  8. 尽管所有信息都在 Git 中,审计还是有问题

  9. 大规模运维 GitOps 很困难

  10. GitOps 和 Helm 并不总是能够很好的合作

  11. 持续部署和 GitOps 不能混为一谈

  12. 没有管理密钥的标准方案

GitOps 只覆盖软件生命周期的一个子集


这是当前 GitOps 工具的主要运作模式,尽管 GitOps(方法论)有一些有趣的特点和卖点,但当前的 GitOps 工具只关注应用程序的部署部分,其他什么都没有。这些工具解决了“我想把 Git 中描述的东西放到集群中”的问题,但是软件开发的所有其他方面都没有涉及到:

GitOps 覆盖范围


之所以提到这一点,是因为 GitOps 工具有时被宣传为万能解决方案,可以解决所有的发行问题,但这是不对的。首先,GitOps 要求所有部署构件已经存在,这意味着……

  • 编译代码

  • 运行单元/集成测试

  • 安全扫描

  • 静态分析

……并不是 GitOps 工具所关心的问题,而是被认为都已经准备好了。


甚至部署问题(例如环境升级、密钥管理、冒烟测试等)也被轻易排除在 GitOps 范式之外,采用 GitOps 的团队需要为软件交付的所有方面创建自己的最佳实践。


因此,不能简单“采用 GitOps 解决方案”并就此结束。GitOps 只是整个发展战略的一部分,应该确保所有其他流程和工作流程已经准备好与 GitOps 合作。

用 GitOps 分割 CI 和 CD 并不容易


GitOps 被认为是一种将 CI 与部署分离的方法。在 CI/CD 系统的经典应用中,流程中的最后一步是部署。


经典流水线


使用 GitOps,可以维持纯粹的 CI 流程,只要将候选版本通过 Git 提交,而不需要部署。Git 提交触发部署解决方案,该方案监听 Git 存储库,并通过在集群中拉取变更来处理实际的部署(从而使集群状态与 Git 状态一致)。


该场景在理论上很完美,也适用于简单的场景,但当涉及到大型组织采用的高级部署时,很快就会崩溃。

混合 CI 和 CD 的典型例子是冒烟测试,有时候我们希望在部署完成后运行冒烟测试,并根据测试的结果决定是否回滚变更。


冒烟测试


正如前面所说,GitOps 只处理部署构件,通常不涉及(或不了解)源代码,但是在大多数情况下,为了运行单元测试,我们需要访问应用程序的源代码。


当前的 GitOps 工具不能运行单元/集成测试,因为这要求能够看到源代码以及测试所需的所有框架和库。这意味着,为了运行冒烟测试,不得不再次回到 CI 解决方案。


最终的结果是 CI-CD-CI-CD 组件的混合,这违背了 GitOps 的主要精神。当然还有一些潜在问题,比如不知道环境何时完成部署以触发测试。


基于传统的 CI/CD 流水线执行相同的场景会很简单。

GitOps 无法将发布部署到不同的环境中


这可能是关于 GitOps 讨论最多的问题之一,也是当谈到 GitOps 如何在大型组织中工作时最先讨论的话题之一。


环境升级


考虑一个常见场景:在 Git 中合并(或创建提交),环境 X 的集群现在部署了新版本,但是如何将这个版本部署到环境 Y 中呢?


每当有人宣称采用 GitOps 很简单时,我总会问他们在不同环境之间的部署是如何工作的,但总是得到不同的答案:

  1. “我们用 CI 系统来做到这一点。”这意味着再次将 CI 和 CD 混在一起,并且承认 GitOps 无法覆盖这一场景。

  2. “我们为其他环境开一个新的 pull request。”这意味着必须为每个环境使用不同的 Git 分支(稍后会详细介绍),并且还需要引入更多的手动步骤,以便部署发布。

  3. “我们只有一个环境。”这可能适合小公司,但在其他情况下不可行。


很令人失望,就连专门为解决 GitOps 问题而创建的页面[2]都说:

“GitOps 并没有提供一个将变更从一个阶段传播到下一个阶段的解决方案。我们建议只使用一个环境,并避免多阶段传播。”


处理不同环境的最流行的方法似乎是使用不同的 Git 分支,但这个解决方案有几个缺点:

  • 人们有可能会在特定分支上提交特定于某个环境的代码。

  • 项目有可能会耦合到特定的环境(而不是通用的)。

  • 这给 CI 系统带来了不必要的压力,它必须检查/重建/单元测试每个独立的分支。


此外,如果有很多环境,多分支处理可能会很快失控。

对于多环境配置建模没有标准实践


上一个问题的结论是,如果我们需要多环境部署,那么 GitOps 在没办法帮助我们。事实上,它会迫使我们采用特定的 Git 分支模式(每个环境用特定分支),从而让事情变得更糟。


一个典型例子是,每个地理区域(每个大陆或每个国家)都有不同的环境。


假设我们的应用部署在 10 个国家,我们希望一个国家一个国家的推广版本,GitOps 有什么解决方案?


  • 一个有 10 个分支的存储库,这意味着需要在每次发布时开 10 个 pull request。

  • 10 个 Git 存储库,这意味着需要编写自己的解决方案,在存储库之间复制提交(或者使用 Pull Requests)。

  • 一个包含 10 个子文件夹的 Git 存储库,同样需要外部解决方案来确保更改同步到所有文件夹。


不管哪种方案,发布过程都非常繁琐,目前的 GitOps 工具对于哪种才是标准方案还没有给出答案[3]

自动扩容和动态资源管理破坏 GitOps


在部署完成后,集群状态与 Git 存储库中描述的完全相同,这是 GitOps 的关键点。


在大部分简单的情况下,这没有问题,但一旦我们引入了变量,GitOps 工具就会出现冲突,典型例子如下:

  • 配置了 autoscaler 的集群的副本个数

  • 配置了 optimizer 的集群的资源限制

  • 外部工具添加的额外属性(特别是带有日期或时间戳的值)


一旦集群状态发生变化,GitOps 工具就会尝试从 Git 同步初始值,但在大多数情况下这违背了我们的期望。


状态差异


Argo 支持自定义差异[4],Flux 也有相关建议[5],但这些变通方法只是简单的 hack 了 GitOps,背离了 GitOps 的主要承诺,从长期看会产生其他一些问题[6]

对于回滚没有最佳实践


集群历史的所有记录都在 Git 中,这使得在 GitOps 中回滚(据说)非常容易。如果想回滚到以前的版本,只需要对以前的某个提交应用同步操作就行了。


然而在实践中,“使用以前的提交”的确切含义并不明确,因此不同的人会使用不同的回滚方式:

  1. 简单的将集群指向一个以前的 Git 哈希值,然后让 GitOps 工具同步这个哈希值。这是最快的回滚方式,但根据定义,由于集群不包含上次 Git 提交中所描述的内容,因此会使集群处于不一致的状态。

  2. 使用标准的 Git reset, Git revert 命令,然后让 GitOps 工具像往常一样执行同步操作。这保证了 GitOps 的承诺(在集群中拥有 Git repo 中的内容),当然,这需要手工干预。

  3. 可以组合采用上面 2 种方式,GitOps 工具将之前的 Git 哈希同步到集群,并自动提交(或还原)到 Git repo,以保持一致性。这非常复杂,并且不是所有团队都想让部署工具对 Git repo 有写权限。


不用说,不同的人可能希望使用完全不同的回滚方案。然而,在撰写本文时,目前的 GitOps 工具对于如何以标准方式执行回滚只有很少的支持和指导。

GitOps(和 Git)的可观察性不成熟


GitOps 非常适合查看集群状态,并保证与 Git 状态相匹配。然而,Git 的哈希和提交只对开发和运维人员有用,业务相关方对集群中部署了什么 Git 哈希不感兴趣。


因此,尽管 GitOps 在技术层面上的可观察性很好,但更重要的是要记住,在软件团队中有一些更有用的问题:

  • 生产环境是否包含特性 X?

  • 特性 X 是否清除了预发环境?

  • bug X、Y 只出现在预发环境还是也出现在生产环境?


对于大多数产品所有者和项目经理来说,这类问题非常重要,应该尽快找到答案。


目前,GitOps 工具工作在最低级别(即 Git 哈希值),并且与每个部署的业务价值没有任何关联,开发/运维人员需要找到产品部署和业务价值之间的关联。


在目前的状态下,GitOps 工具在技术层面上非常适合观察集群的内容,但是在监控每个部署的业务指标方面却很糟糕。

尽管所有信息都在 Git 中,审计还是有问题


上一点的推论是,仅仅因为可以以 Git 提交的形式访问集群的整个部署历史,并不意味着可以轻松审计它的功能。


当前的 Git 工具非常适合管理 Git 哈希,但是当涉及到搜索和理解业务价值时,正如 Adam 在 Lack of Visibility[7]中提到的那样,只能提供简单的自由文本搜索功能。


假设我们正在某个特定项目中使用 GitOps,并且知道 Git 历史记录与集群历史记录相匹配,仅仅通过查看 Git History,可以多快回答以下问题?


  • 特性 X 在投入生产之前在预发环境中停留了多长时间?

  • 前两个月的最差、最好和平均交付时间(从开发人员执行提交到实际投入生产的时间)是多少?

  • 对环境 X 的部署成功百分比是多少,需要回滚的百分比是多少?

  • 有多少特性在环境 X 中存在但在环境 Y 中还没有?


这些问题在大型软件团队中很常见,除非在部署平台上有专门的工具,否则仅通过访问 Git 存储库及其历史来回答这些问题是非常困难的。

大规模运维 GitOps 很困难


Adam 在“Git 库的扩展”[7]一文中也提到了这一点。如果在拥有大量环境和应用的大公司中采用 GitOps,那么 Git 存储库的数量会迅速飙升。


这使得跟踪每个环境中正在发生的事情变得非常困难,并且可能很快导致配置冗余或者人们不得不向特定环境提交(而不是使用共享配置)。


例如,如果我们有 20 个存有 Kubernetes manifests 的 git 仓库,当我们需要完成一个重要变更(例如,在每个部署中添加一个新的全公司范围的标签),需要手动完成 20 个 git 提交,或者创建一些胶水代码来帮我们完成。


另一方面,可以为所有环境(或集群)提供一个 Git 存储库,在这些环境中,所有人都与 CI/CD 系统协作。


但正如 Adam 所解释的那样,这就产生了 Git 冲突的问题(Git 存储库和很多 CI 流程交互,由于 Git 仓库在这一过程中发生了变更,造成推送失败)。


拥有一个巨大的 Git 存储库会很快成为 GitOps 流程的瓶颈,这会在扫描存储库进行更改时引入性能问题。

GitOps 和 Helm 并不总是能够很好的合作


Helm 是 Kubernetes 的包管理器,通常被视为在集群中部署第三方应用程序的事实标准,当然也可以用于自己的部署。


Helm 的工作方式是将 Kubernetes manifests 的一组模板及其运行时值结合起来,这些模板被合并从而最终完成集群的部署。


当 Helm 安装一个发布时,我们可以提供 values.yml,最好的做法是将 values 文件提交给 Git,可以为每个环境(例如 qa/预发/生产)提供不同的 values。


Helm 本身并没有规定这 3 个组件(源代码、manifests、values)应该保存在哪里。可以将它们全部保存在同一个 Git 存储库中,也可以将它们保存在三个不同的存储库中。然而,普遍接受的做法是,如果我们有不同环境的 values,可以将它们与模板保存在不同的位置,模板(chart 本身)存储在 chart 存储库中,每个环境的特定 values 存储在 git 存储库中。


这意味着在部署过程中必须完成以下步骤:

  1. 从 chart 存储库中下载 chart

  2. 从 Git 存储库中获取 values

  3. values 和 chart 合并,从而创建一组 Kubernetes manifests

  4. 在集群上应用这组 manifests


这仅用于初始部署。按照 GitOps 范例,应该监视包含 values 文件的 Git 存储库以及 chart 存储库中的 chart。如果它们的合并结果与集群状态不同,则应该进行新的部署。


在撰写本文时,Flux[8]和 ArgoCD 都不支持这个基本的 Helm 场景。如果希望采用基于 Helm chart 的 GitOps,那么必须采用一些变通方法和限制,从而使这一过程变得比需要的复杂得多。

持续部署和 GitOps 不能混为一谈


GitOps 是一个很棒的持续交付解决方案,每个提交都会产生一个发布候选版本,并将其推向生产环境。另一方面,持续部署是直接提交到生产的整个过程,无需任何人工干预[10]


如果作为开发人员,可以在周五下午提交变更,然后立即开始享受周末,那么就是在实践持续部署,提交的变更将在几分钟内通过所有质量检查和测试后投入生产。


根据定义,GitOps 是由包含 manifests 的仓库上的 Pull Request 驱动的。在大多数情况下,需要人工审查和批准这些 Pull Request,这意味着实践 GitOps 至少需要一些手动步骤来处理这些 Pull Request。


理论上,人们可以通过完全自动化的 Pull Request 来实现持续部署,同时仍然采用 GitOps。然而,当前的 GitOps(和 Git)工具并没有考虑到这种自动化,所以如果你想走这条路,就只能靠自己了。


记住,持续部署并不是圣杯。对于一些组织来说,持续交付已经足够了,在某些情况下,甚至可能受到法律的约束,必须明确禁止完全自动化的部署。


但是如果想要更快的交付时间,GitOps 并不是最好的解决方案。

没有管理密钥的标准方案


这是 GitOps 的一个众所周知的问题,所以为了表述完整,我也把它包括进来。密钥处理是软件部署最重要的方面之一,然而,GitOps 并没有解决这一问题。


关于如何管理密钥,目前还没有公认的做法。如果将密钥存储在 Git 中,则需要进行加密,并且在部署过程中采用自己的工作流。如果不存储在 Git 中,那么让集群状态与 Git 相同的想法就不再正确了。


每个公司的密钥管理都有自己的解决方案,所以我希望 GitOps 工具能够提供一个开箱即用的解决方案。


References:

[1] The pains of GitOps 1.0: https://codefresh.io/about-gitops/pains-gitops-1-0/

[2] GitOps: https://www.gitops.tech/

[3] Document best practises on working with multiple environments: https://github.com/fluxcd/flux/issues/1071

[4] Diffing Customization: https://argoproj.github.io/argo-cd/user-guide/diffing/

[5] How can I prevent flux overriding the replicas when using HPA: https://docs.fluxcd.io/en/1.17.0/faq.html#how-can-i-prevent-flux-overriding-the-replicas-when-using-hpa

[6] Maintain difference in cluster and git values for specific fields: https://github.com/argoproj/argo-cd/issues/2913

[7] Lack of Visibility: https://blog.container-solutions.com/gitops-the-bad-and-the-ugly

[8] Flux helm repository chart updates: https://docs.fluxcd.io/projects/helm-operator/en/latest/helmrelease-guide/automation/#helm-repository-chart-updates

[9] Helm chart + values files from Git: https://github.com/argoproj/argo-cd/issues/2789

[10] What the Heck Is Continuous Integration (CI), Delivery (CD), and Deployment (CDP)? https://codefresh.io/continuous-deployment/heck-continuous-integration-ci-delivery-cd-deployment-cdp/


你好,我是俞凡,在 Motorola 做过研发,现在在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓厚的兴趣,平时喜欢阅读、思考,相信持续学习、终身成长,欢迎一起交流学习。

微信公众号:DeepNoMind

发布于: 刚刚阅读数: 4
用户头像

俞凡

关注

公众号:DeepNoMind 2017.10.18 加入

俞凡,Mavenir Systems研发总监,关注高可用架构、高性能服务、5G、人工智能、区块链、DevOps、Agile等。公众号:DeepNoMind

评论

发布
暂无评论
GitOps的12个痛点_DevOps_俞凡_InfoQ写作平台