作者:dholbach
自从 Flux 获重写为一组聚焦的控制器以来,它的每个功能和能力变得更加清晰。适当命名的控制器以它们的名字携带它们所负责的内容,以及它们与哪些数据或工具交互,例 source、kustomize、image-automation、notification、helm,等等。
如果你想将 GitOps 工具的概念验证串在一起,一个简单的解决方案可能是使用各种工具,如 curl、git、kubectl 和 helm。虽然这一开始可能感觉很直观(因为它非常类似于使用键盘的手动工作流),并且可能很快,而且基本上能跑能用,但在随后的细化阶段,这需要付出很大的代价:充分捕捉错误、提供详细的状态信息、安全性考虑、命令行工具和基础设施实现之间的不匹配、API 和 CLI 版本,等等。
在 Flux 项目开始以来的过去五年中,我们已经看到了上述所有情况以及更多情况。因为其他项目犯了这些错误,或者因为我们自己犯了这些错误。
让我们更深入地探讨一下,为什么我们投入如此多的精力来尽可能紧密地集成给定的工具 API 和 SDK。
没有 Git 就没有 GitOps,所以我们显然希望支持所有的 Git 提供者、所有的边缘情况、所有不同的设置方式,以及我们需要的所有 Git 操作。例如,当我们在远程 Git 仓库上执行克隆和推送操作时,就会与 Git 发生明显的交互。
对任何代码路径使用 CLI 应该是最后的手段——如果有的话。Flux 控制器的设计原则是不这样做。我们避免了一整类的漏洞:命令注入(command injection)。
当我们开始处理 source-controller 时,放弃 Git CLI 的另一个重要原因是多租户。Git CLI 希望将 SSH 和 PGP 密钥放在磁盘上,而我们希望从内存中加载它们来隔离租户的秘密,而不必将它们写在磁盘上,以免遭受目录遍历攻击(directory traversal attack)。
总之,我们选择不依赖现有的 Git 二进制文件,而是针对一个已知良好且经过充分测试的版本进行静态链接。更多信息请见下文。
我们开始对所有 git 操作是使用go-git[1],因为它是完全用 Go 编写的 Git 协议的实现。当我们想要支持 Azure DevOps 并看到 go-git 中不包含对 multi_ack 和 multi_ack_detailed 的支持时,我们开始另外使用git2go[2]。它是libgit2 库[3]的 Go 绑定,对 git 协议中更复杂的功能有更大的支持,包括git 协议版本 2[4]。不幸的是,git2go 不支持浅层克隆(shallow clone)或 git 子模块。我们的实现目前还不支持新添加的对使用 SSH 密钥进行提交签名的支持。
虽然以上听起来像是琐碎的实现细节,但我们必须自己学习了解每个 Git 实现都有自己的缺点。在 Git CLI 中“正常工作”的东西,任何实现都会出现微妙的错误,因为它们在 Git 的“管道(plumbing)[5]”级别上工作。最后,我们选择让 gitImplementation 成为一个可配置的设置[6]。
为了说明当你试图把事情做得恰到好处时会发生什么,下面是我们在这个过程中需要完成的几件工作:
随着 Git 变得无处不在,几乎世界上所有的软件开发都依赖于 Git,它仍然处于积极的开发中。不断的改进会影响功能、效率、可配置性和更好的安全性。当然,我们希望将这一切传递给我们的用户:更高效的下载带来了巨大的变化,对 Git 子模块的支持支持了新的用例,对更多 GPG 验证或新 SSH 密钥格式的支持增加了额外的安全性,当 Git 提供商推出新功能时,我们也需要在 Flux 支持它们。
不幸的是,将这些变化融入 Flux 并不像听起来那么容易。git2go 依赖链的一部分是这样的:
libgit2 -> libssh2 -> OpenSSL
这就是libgit2[8]、libssh2[9](以支持 ssh 传输)和OpenSSL[10]。由于 Linux 供应商通常采取非常保守的方法将新的软件版本引入稳定版本,我们很不幸地被迫自己构建这些依赖关系[11]。除此之外,这些库有相当多的配置选项只能在构建时设置,不幸的是,不同 Linux 发行版的 openssl/libssh2 包的行为方式略有不同[12]。这又产生了个不同的问题:当我们在 Mac/Linux 机器上开发时,我们在容器中发布的版本可能会有不同的行为。这迫使我们交叉编译静态构建的库,我们可以在开发时简单地下载这些库,或者在发布控制器时将它们静态链接到我们创建的最终二进制文件中。
我们决定为 AMD64、ARM64 和 ARMv7 架构构建库,并静态链接它们,这是我们为所有 Flux 控制器启用 fuzzing[13]的先决条件。为每个上游版本设置并运行这些,并确保测试很好地覆盖了是个挑战,也是我们投入了大量时间的工作领域。
libgit2 没有暴露允许用户为网络操作设置超时的概念,这意味着大多数 git 操作可能会在特定环境下无限期挂起。这将导致特定的 GitRepository 对象被卡住,并停止更新,直到控制器重新启动——用户在过去 6 个月中报告了 image-automation 和 source 控制器的这种情况。
我们遇到了一些挑战,要求上游进行更改以修复类似的问题,因此为了避免延迟修复或依赖性分叉,我们决定添加对 Go 托管传输的实验性支持,这意味着我们可以强制网络操作不会花费超过给定时间来完成,但不需要上游进行任何更改。
这是Flux 0.28[14]的一部分,可以通过在 source 和 image-automation 控制器中添加一个环境 EXPERIMENTAL_GIT_TRANSPORT=true 来实现。
这将使我们能够使用 libgit2 智能传输支持,通过 Go native transport 对传输进行更多的控制。有关更多信息,请阅读源代码控制器变更日志。
如果你想自动启用它,只需将以下内容添加到 kustomization.yaml 中:
patches:
- patch: |
- op: add
path: /spec/template/spec/containers/0/env/0
value:
name: EXPERIMENTAL_GIT_TRANSPORT
value: "true"
target:
kind: Deployment
name: "(source-controller|image-automation-controller)"
对 sha256 哈希的支持:Git CLI 从 2.29 开始支持它,但是所有主要的 Git 服务提供商,如 GitLab 和 GitHub,都还没有在这方面取得一些进展。在上游,libgit2 在v1.4.0[15]上开始了支持的工作,我们将继续关注这一领域,以便随着行业从 SHA1 向前发展,我们可以支持 Flux 用户。
经过过去几个月对稳定性的大力关注,我们现在要看看如何优化我们的 git 实现,以减少跨 git 协调的资源消耗和网络流量。
Flux 不支持像 git、helm 或 kubectl 这样的二进制程序,因为我们认为它太容易出错,而且我们会错过为你带来最佳开发体验和每一步最准确信息的大好机会。这样我们可以为你提供更多的控制。你可能已经从这些对我们来说意味着额外工作的数量中了解到,我们非常重视“GitOps”中的“Git”。
我们喜欢反馈、问题和想法,所以请今天就告诉我们你的个人使用案例。如果你有任何问题,请询问我们:
再见!
[1]go-git: https://github.com/go-git/go-git
[2]git2go: https://github.com/libgit2/git2go
[3]libgit2 库: https://libgit2.org/
[4]git 协议版本 2: https://git-scm.com/docs/protocol-v2
[5]管道(plumbing): https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
[6]可配置的设置: https://fluxcd.io/docs/components/source/gitrepositories/#git-implementation
[7]打破已知主机的工作方式: https://github.com/fluxcd/source-controller/commit/9479d04779ccb7fc44b972cde23cb9a6c052f445
[8]libgit2: https://libgit2.org/
[9]libssh2: https://libssh2.org/
[10]OpenSSL: https://www.openssl.org/
[11]自己构建这些依赖关系: https://github.com/fluxcd/golang-with-libgit2#rationale
[12]略有不同: https://github.com/fluxcd/golang-with-libgit2/blob/libgit2-1.3.0/hack/Makefile#L63-L69
[13]启用 fuzzing: https://fluxcd.io/blog/2022/02/security-more-confidence-through-fuzzing/
[14]Flux 0.28: https://github.com/fluxcd/flux2/releases/tag/v0.28.0
[15]v1.4.0: https://github.com/libgit2/libgit2/releases/tag/v1.4.0
[16]即将召开的开发人员会议: https://fluxcd.io/community/#meetings
[17]CNCF Slack: https://slack.cncf.io/
[18]采纳者: https://fluxcd.io/adopters/
CNCF (Cloud Native Computing Foundation)成立于2015年12月,隶属于Linux Foundation,是非营利性组织。
CNCF(云原生计算基金会)致力于培育和维护一个厂商中立的开源生态系统,来推广云原生技术。我们通过将最前沿的模式民主化,让这些创新为大众所用。