werf 收集器中基于内容的标记:它为何以及如何工作?

werf 收集器中基于内容的标记:它为何以及如何工作?

韦尔夫 是我们的开源 GitOps CLI 实用程序,用于构建应用程序并将其交付到 Kubernetes。 在 发布v1.1 图像收集器中引入了一项新功能:按内容或标记图像 基于内容的标签。 到目前为止,werf 中的典型标记方案涉及通过 Git 标记、Git 分支或 Git 提交来标记 Docker 镜像。 但所有这些方案都有缺点,新的标记策略完全解决了这些缺点。 有关它的详细信息以及它为何如此出色的内容都在下文中。

从一个 Git 存储库推出一组微服务

当应用程序被分为许多或多或少独立的服务时,经常会发生这种情况。 这些服务的发布可以独立进行:一次可以发布一个或多个服务,而其余服务必须继续工作而不做任何更改。 但从代码存储和项目管理的角度来看,将此类应用程序服务保存在单个存储库中更为方便。

在某些情况下,服务是真正独立的并且不与单个应用程序关联。 在这种情况下,它们将位于不同的项目中,并且它们的发布将通过每个项目中单独的 CI/CD 流程进行。

然而,实际上,开发人员经常将单个应用程序拆分为多个微服务,但为每个微服务创建单独的存储库和项目......显然是一种矫枉过正。 我们将进一步讨论这种情况:多个此类微服务位于单个项目存储库中,并且通过 CI/CD 中的单个流程进行发布。

通过 Git 分支和 Git 标签进行标记

假设使用最常见的标记策略 - 标签或分支。 对于 Git 分支,图像用分支名称进行标记,对于一个分支,一次只有一个以该分支名称发布的图像。 对于 Git 标签,图像根据标签名称进行标记。

当创建新的 Git 标签时(例如,发布新版本时),将为 Docker 注册表中的所有项目映像创建一个新的 Docker 标签:

  • myregistry.org/myproject/frontend:v1.1.10
  • myregistry.org/myproject/myservice1:v1.1.10
  • myregistry.org/myproject/myservice2:v1.1.10
  • myregistry.org/myproject/myservice3:v1.1.10
  • myregistry.org/myproject/myservice4:v1.1.10
  • myregistry.org/myproject/myservice5:v1.1.10
  • myregistry.org/myproject/database:v1.1.10

这些新的镜像名称通过 Helm 模板传递到 Kubernetes 配置。 使用命令启动部署时 werf deploy 字段正在更新中 image 在 Kubernetes 资源清单中,由于镜像名称更改而重新启动相应的资源。

问题:事实上,自上次推出(Git 标签)以来,镜像的内容没有发生变化,而只有 Docker 标签发生变化,就会发生这种情况 过量 重新启动此应用程序,因此可能会出现一些停机时间。 尽管没有真正的理由执行此重启。

因此,使用当前的标记方案,有必要隔离几个单独的 Git 存储库,并且出现了组织这几个存储库的推出的问题。 一般来说,这样的方案结果是超载且复杂的。 最好将许多服务合并到一个存储库中并创建 Docker 标签,这样就不会出现不必要的重启。

通过 Git 提交标记

werf 还有一个与 Git 提交相关的标记策略。

Git-commit 是 Git 存储库内容的标识符,依赖于 Git 存储库中文件的编辑历史记录,因此使用它来标记 Docker 注册表中的图像似乎是合乎逻辑的。

但是,通过 Git 提交进行标记与通过 Git 分支或 Git 标签进行标记具有相同的缺点:

  • 可以创建一个不更改任何文件的空提交,但映像的 Docker 标记将被更改。
  • 可以创建不更改文件的合并提交,但图像的 Docker 标记将被更改。
  • 可以进行提交来更改 Git 中未导入到映像中的那些文件,并且映像的 Docker 标记将再次更改。

标记 Git 分支名称不反映镜像版本

还有另一个与 Git 分支的标记策略相关的问题。

只要按时间顺序顺序收集该分支上的提交,就可以按分支名称进行标记。

如果在当前方案中,用户开始重建与某个分支关联的旧提交,那么 werf 将使用相应的 Docker 标签和旧提交的新构建版本的映像来重写映像。 从现在开始,使用此标签的部署在重新启动 pod 时存在拉取不同版本映像的风险,因此我们的应用程序将失去与 CI 系统的连接并变得不同步。

此外,如果连续推送到一个分支且时间间隔很短,则旧提交的编译时间可能会晚于新提交:旧版本的映像将使用 Git 分支标签覆盖新版本。 此类问题可以通过 CI/CD 系统来解决(例如,在 GitLab CI 中,后者的管道是针对一系列提交启动的)。 然而,并非所有系统都支持这一点,必须有更可靠的方法来防止这种根本问题。

什么是基于内容的标记?

那么,什么是基于内容的标记——按内容标记图像。

要创建 Docker 标签,使用的不是 Git 原语(Git 分支、Git 标签...),而是与以下内容关联的校验和:

  • 图像的内容。 图像ID标签反映其内容。 当构建新版本时,如果镜像中的文件没有改变,这个标识符也不会改变;
  • 在 Git 中创建此图像的历史记录。 与不同 Git 分支和通过 werf 的不同构建历史关联的映像将具有不同的 ID 标签。

这样的标识符标签就是所谓的 图像阶段签名.

每个图像由一组阶段组成: from, before-install, git-archive, install, imports-after-install, before-setup,... git-latest-patch ETC。 每个阶段都有一个反映其内容的标识符 - 舞台签名 (舞台签名).

由这些阶段组成的最终图像被标记为这些阶段组的所谓签名 - 阶段签名, - 这概括了图像的所有阶段。

对于配置中的每个图像 werf.yaml 一般情况下,会有自己的签名,以及相应的 Docker 标签。

阶段签名解决了所有这些问题:

  • 抵抗空 Git 提交。
  • 抵抗 Git 提交更改与图像不相关的文件。
  • 当为分支的旧 Git 提交重新启动构建时,不会导致彻底修改当前版本的映像的问题。

这是现在推荐的标记策略,也是所有 CI 系统 werf 中的默认策略。

如何在werf中启用和使用

该命令现在有相应的选项 werf publish: --tag-by-stages-signature=true|false

在 CI 系统中,标记策略由命令指定 werf ci-env。 之前为它定义了参数 werf ci-env --tagging-strategy=tag-or-branch。 现在,如果您指定 werf ci-env --tagging-strategy=stages-signature 或者不指定该选项,werf将默认使用标记策略 stages-signature. 库玛纳达 werf ci-env 将自动为命令设置必要的标志 werf build-and-publishwerf publish),因此不需要为这些命令指定其他选项。

例如,命令:

werf publish --stages-storage :local --images-repo registry.hello.com/web/core/system --tag-by-stages-signature

...可以创建以下图像:

  • registry.hello.com/web/core/system/backend:4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d
  • registry.hello.com/web/core/system/frontend:f44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6

这是 4ef339f84ca22247f01fb335bb19f46c4434014d8daa3d5d6f0e386d 是图像阶段的签名 backendf44206457e0a4c8a54655543f749799d10a9fe945896dab1c16996c6 - 图像阶段的签名 frontend.

使用特殊功能时 werf_container_image и werf_container_env 无需更改 Helm 模板中的任何内容:这些函数将自动生成正确的图像名称。

CI 系统中的配置示例:

type multiwerf && source <(multiwerf use 1.1 beta)
type werf && source <(werf ci-env gitlab)
werf build-and-publish|deploy

有关配置的更多信息可在文档中找到:

在总

  • 新选项 werf publish --tag-by-stages-signature=true|false.
  • 新的期权价值 werf ci-env --tagging-strategy=stages-signature|tag-or-branch (如果没有指定,则默认为 stages-signature).
  • 如果您之前使用过 Git 提交的标记选项 (WERF_TAG_GIT_COMMIT 或选项 werf publish --tag-git-commit COMMIT),那么一定要切换到标记策略 阶段签名.
  • 最好立即将新项目切换到新的标记方案。
  • 转移到werf 1.1时,建议将旧项目切换到新标记方案,但旧项目 标签或分支 仍然支持。

基于内容的标记解决了本文中涉及的所有问题:

  • Docker 标记名称对空 Git 提交的抵抗力。
  • Docker 标签名称对 Git 提交的弹性,可更改与映像无关的文件。
  • 当重新启动 Git 分支的旧 Git 提交构建时,不会导致彻底修改当前版本的镜像的问题。

用它! 并且不要忘记访问我们 GitHub上创建问题或查找现有问题、给予加分、创建 PR 或只是观察项目的开发。

PS

另请阅读我们的博客:

来源: habr.com

添加评论