你可能遇到过这个由盛行的云计算软件工程师Kelsey Hightower分享的关于GitOps的简要介绍。

在基础设施即代码的世界里,GitOps是一种流行的方式,通过持续集成/持续开发(CI/CD)和一般的微服务架构来管理自动化部署,因为我们今天的大部分基础设施基本上都是用配置文件定义的(例如YAML、JSON、HCL)。这并不限于Kubernetes(K8s),但它往往与K8s集群高度相关。(我稍后会解释原因。)这基本上意味着,改变你的生产基础设施中的任何东西都像改变一行代码一样简单。

GitOps之所以与K8s如此紧密地联系在一起,是因为K8s完全是用声明性的YAML来配置的,因此,你可以快速实现使用GitOps的好处,因为它实际上只是软件定义的基础设施。谈到在你的工程组织中正确应用GitOps,你需要注意的主要事情是如何强制改变你的集群或基础设施。

当你选择GitOps路径时,你只能通过一个单一的真理来源:你的源代码管理(SCM)仓库(例如GitLab、GitHub、Bitbucket或你自己的托管解决方案),为整个组织执行版本控制策略。这意味着对你的基础设施进行修改的唯一途径是通过在你的存储库中提出拉动请求。这就是在使用GitOps的大型工程组织中大规模维护版本控制的方式。

现实世界中的部署状况

GitOps理论声称是实现CI/CD的新的、更简单的方法,只是CI/CD的CD部分是一个比GitOps实践所认为的更复杂的野兽。在GitOps中,CD部分被分解为对工程环境的一种非常二元的方法。你要么在暂存环境中,要么在生产环境中,你只要按一下开关,你的代码就会进入生产环境。在我多年的工程师经验中,我还没有参与过如此简单的重大代码变更、功能推出或其他重大部署。

在GitOps中,从CD过程中完全抽象出来的暂存或生产版本还有很多工作要做。这意味着,任何认真对待质量的工程流程都会在重大部署的CI和CD阶段之间有几个阶段。这些阶段包括测试、验证结果、验证变化是否传播、重新测试,以及经常进行部分推广(金丝雀之类的)。这些只是工程组织中管理CD的几个例子。

GitOps的部署技巧

说到GitOps,没有必要重新发明CI/CD(尤其是CD)轮子。如果你像大多数人一样,通过在部署前后用一些定制的脚本来实现CI/CD流程,以使其通过终点线,那么你应该知道有更好的方法来使用GitOps促进器。使用GitOps促进器,如开源的云原生计算基金会(CNCF)托管的Argo CD,使用户能够在一个地方采取所有这些自定义脚本并对其进行大规模管理。这确保了在你的CI/CD过程中使用脚本时的最佳实践,使它们每次运行时都是规范和可重复的。

更重要的是,由于有一个持续同步状态的代理,它通过强制执行已提交的状态来减少人为错误。

用GitOps管理跨仓库的混乱局面

对于复杂的部署架构,如K8s,甚至是普通的微服务,即使是对代码的小改动也会影响到其他相互依赖的服务。用GitOps来映射这些依赖关系往往会成为一个地狱般的场景。通常在共享仓库和文件的情况下,你需要同步状态。然而,你还会经常发现,错误、错误配置,甚至只是bug,都会产生蝴蝶效应,引发一连串的故障,在GitOps中变得极难跟踪和理解。

解决GitOps的这一难题的一个常见方法是创建一个 “超级 repo”,它基本上是一个集中的单版本,包含所有相关的依赖、文件、资源等的指针。然而,这很快就变成了一个混乱的垃圾袋,很难理解、跟踪和记录变化。

当你有许多依赖关系时,为了在GitOps中发挥作用,这些依赖关系需要在Git中得到体现。这就要求你的组织成为 “Git native”。这意味着你需要做大量的管道自动化工作,以创建模块和子模块来连接和关联你的超级仓库和相关子仓库。很多时候,这伴随着大量的维护开销,随着时间的推移,维护起来变得非常困难。

如果你不这样做,你就无法实现GitOps的好处,而你大多只能忍受其缺点。你可以通过一个YAML文件来实现类似的功能,该文件封装了所有的版本和依赖关系,类似于Helm的伞形图。如果不完全采用Git原生系统,你基本上可以成为其他任何东西,而不是GitOps。

虽然在GitOps的世界里,仓库代表了环境的单一真理来源,但在实践中,任何特定的部署都有许多第三方的集成。这些集成可以是任何东西,从你的认证和授权(例如Auth0)到你的数据库,在大多数情况下,这些都是在你的 repo 外部更新的。这些对外部资源的变化可能会对你的生产和部署产生重大影响,但在你的单一真理来源的 repo 中却没有任何表示。这可能是整个部署中的一个严重盲点。

GitOps管理混乱的技巧

在使用GitOps时,要像对待代码一样对待你的配置。不要吝惜验证管道,确保适当的拉动请求卫生,并保持你在大规模管理代码时应用的任何其他做法,以避免这种混乱。不要惊慌!如果有什么不正确的东西被推送,你担心它会传播到所有的服务器、集群和仓库,你所需要做的就是运行git revert ,你可以撤销你的最后提交。

另外,与我关于同步状态的建议类似,使用GitOps促进者可以帮助管理Git实践,成为Git原生,并处理Kubernetes部署(也是Kubernetes原生)。

最后,为了避免任何混乱或复杂,确保你的Git仓库的状态尽可能地接近你的生产环境,以避免你的环境在GitOps操作中出现任何漂移。

使用GitOps的3个提示

以下是我对如何充分利用GitOps的建议。

  1. 确保尽早建立GitOps自动化的可视性,这样你就不会在众多仓库中盲目运行。当涉及到让GitOps最佳地工作时,你应该在每个应用的单一仓库中工作。当这些东西开始增加的时候,可见性就会成为一个真正的痛点。考虑一下依赖关系,以及如何在系统中设计足够的可视性,这样如果出了问题,你就知道如何追踪它的源头并加以修复。
  2. 做到这一点的一个方法是为每一种故障情况做计划。依赖关系崩溃时会发生什么?当涉及到GitOps时,合并冲突是一种生活方式。你如何管理高速的部署和向生产的推广,这可能会使GitOps系统不堪重负?想一想许多潜在的挑战、失败和冲突,并为每一种情况制定一个操作手册。另外,在第一点的基础上,确保每一个问题都有足够的可视性,以便迅速排除故障。当然,不要忘记在故障发生时使用git revert 命令。
  3. 使用monorepo。在这里,我说了。老生常谈的单版本与多版本之争。说到GitOps,毫无疑问哪个是更好的选择。虽然集中式单仓库有缺点(例如,它可能会变得混乱,成为理解构建过程的噩梦,等等),但它也可以帮助解决大部分跨仓库依赖的麻烦。

作为一名工程师,我直接感受到了这种痛苦。我意识到,在我的GitOps生活中,我每天都在感受着这些依赖性和可见性的挑战,因此迫切需要一些东西来关联这些依赖性和可见性。

我想要一个更好的解决方案来跟踪复杂的微服务设置中的故障,并将其级联到根本原因或代码更改。到目前为止,我所尝试的一切,包括GitOps,都只提供了部分信息,很少有相关性,而且几乎没有因果关系。

GitOps工具(如Argo CD)有助于解决DIY GitOps中出现的许多问题。在走GitOps路线时,使用这类工具可以考虑,因为它们。

  • 是为Kubernetes设计的原生工具
  • 适合小团队使用image-puller
  • 有强大的社区支持(例如,通过CNCF的Argo CD,它也很容易与其他Argo工具一起使用
  • 通过良好的用户界面为应用程序提供更好的开发者体验
  • 与Git天然集成,这有助于减少混乱和复杂性

底线

部署过程,尤其是新版本的部署,是一项_复杂的_工程壮举。要做好这些,你需要在技术和流程设计上都投入精力。例如,在生产中部署和验证我的应用程序的最佳方式是什么?

GitOps是一个非常好的起点,可以了解生产中运行的内容。只要记住,它可能还需要用更多的工具和DIY自动化来增强它的功能,让它恰好适合你的工程团队。这样一来,GitOps的光芒对你的组织来说就是24K,而不是傻瓜的黄金。