Helm: 添加“helm install --app-version”命令/针对应用程序版本对图表进行版本控制

创建于 2018-02-22  ·  118评论  ·  资料来源: helm/helm

据我所知, helm install目前仅支持指定--version标志来指定要安装的图表版本。

我不确定应该如何使用 Chart.yaml 中的“appVersion”字段,但添加对针对 Chart 的特定版本(或版本集)对应用程序进行版本控制的支持似乎通常很有用。

我在这里误用了appVersion字段吗? 我是否应该不断地构建我的图表以与以前的版本向后兼容,否则我如何向我的用户推断在运行helm install时指定哪个图表版本,如果他们想要一个特定版本(这变得更加复杂)当您考虑到用户还可以使用诸如--set image.tag类的内容更改部署的版本时,这通常会导致应用程序的版本更改)。

feature

最有用的评论

我完全不明白这个讨论。 为什么不让人们选择以他们认为最适合他们的方式使用应用程序版本是一个大问题?

在我目前的形式中,最好根本没有这个APP VERSION 。 它只会给我们项目中的人们带来混乱。 我们有超过 80 个使用相同舵图的服务,并且因为在helm upgrade -i ...无法轻松更改此APP VERSION helm upgrade -i ...我看到我们所有的应用程序将永远保留1.0在这里。 而且我不打算重新打包已经打包的图表来更改应用程序版本。 为什么我应该使我的 CI 复杂化以适合您的设计???

我也看到我只需要告诉大家不要使用helm list因为这对他们没有用。 要检查他们拥有我们的应用程序的哪个版本,他们需要使用其他东西。

开始阅读这篇谈话时我很乐观,但在看到你如何讨论这个以及你如何努力迫使用户采用你的思维方式后,我现在失去了希望:(。

所有118条评论

我也刚碰到这个。 我通常希望在打包图表时指定图像标签,但为了调试应用程序想要使用不同的标签进行安装。

问题在 90 天不活动后变得陈旧。
使用/remove-lifecycle stale将问题标记为新问题。
陈旧的问题在额外 30 天不活动后腐烂并最终关闭。

如果现在可以安全关闭此问题,请使用/close关闭。

向 sig-testing、kubernetes/test-infra 和/或fejta发送反馈。
/生命周期陈旧

再次提出这个问题,因为它在https://github.com/kubernetes/charts/pull/5919中提出

复制我最近评论的部分内容:


我们特别选择使图表的次要版本与次要应用程序版本保持一致(尽管补丁版本号可以并且确实会分开)。

这是因为我们可能会向 cert-manager 的新版本添加一个新标志,并且通过在 Helm 图表中添加对它的支持会破坏与旧版本的 cert-manager 的兼容性,因为它们不支持该标志。 这是关于一般 IMO 中 Helm 图表版本控制的一个非常基本的问题,我们没有一个好的故事。

我知道不建议尝试将 appVersion 与图表版本对齐,但是这样,用户知道他们可以将 Helm 图表版本 0.3.x 与任何证书管理器 0.3.x 和图表版本 0.4.x 与证书一起使用-经理 0.4.x。 兼容性是在次要版本中定义的。

/删除生命周期陈旧

我想重新讨论这个问题。

总体而言,当所有变化只是某些组件使用的图像标签时,我们还没有看到太多令人信服的支持对我们内部应用程序的图表进行版本控制。 升级版本时, appVersion 字段似乎是此信息的正确位置。

复制我上面提到的原始提案:


我们当前用于部署 helm charts 的工作流程涉及调用 helm upgrade CLI 命令的 ansible 任务,并且在修订同一图表版本的发布时能够传递一个标志来设置 appVersion 会很好。

这在概念上可能有点奇怪,因为 appVersion 与图表而不是发布相关联,但在我们的例子中,我们只是更新用于某些容器的图像标签,我们的工作流程还没有合并图表版本和/或图表存储库然而。 这在未来可能会改变,但目前我认为在安装和升级时为 --app-version 添加标志没有任何问题,因为该字段纯粹是信息性的。

在开发我们自己的内部应用程序时,应用程序本身的变化比部署它的图表要多得多。 通常,我们的持续部署命令是一个helm upgrade ,只有--set imageTag=<new_version> (显然,在图表中的其他地方用于设置容器版本)如果我们用 --app-version 替换它,它将给出我们在helm ls另一个可视点来查看部署的代码版本以及部署的图表版本。

为了使这更明显,否则我已经标准化了设置imageTag的元数据标签,该标签被设置为在安装/升级时传递的 imageTag。 这允许我使用 K8s 仪表板或轻松创建显示 imageTag 的 Graphana 仪表板,但需要我离开命令行并点击鼠标。

有这方面的消息吗?

谢谢

这事有进一步更新吗。 似乎来自@Eraac 的PR 执行了要求的操作。 正如@TD-4242 提到的,我们还运行helm upgrade --set imageTag=<imagetag> ,但这不会更新helm ls输出中列出的应用程序版本。 能够--set app-version--set version将允许我们运行helm upgrade以便helm ls正确显示部署的版本。

任何更新?

Aaaaany time 很快就会很可爱!

这将非常有用

也希望能够在安装时设置应用程序版本,因为我们使用通用图表来部署应用程序

+1

+1

这会很有帮助

要求相同

请通过 +1 停止垃圾邮件。 已经有一个 PR (https://github.com/helm/helm/pull/4961) 并且人们正在讨论该提案。 上次回复甚至是在 2 天前。

@filipre

已经有一个 PR (#4961) 并且人们正在讨论该提案。

根据那个公关,这被移到这里:
https://github.com/helm/helm/pull/5492
这是#4961 的最新 PR,看起来好像我们正在等待合并审查......

@filipre你能说:PR 会发生什么? 貌似PR半个月没动静

这将非常有用。 我遇到了一些需要固定到应用程序版本 0.6.0 的问题,并且图表版本与应用程序版本无关。

我同意,我也认为这将非常有用。 任何更新?

当我意识到这在编写我们计划为许多应用程序重用的 Helm 图表时会出现问题时,现在就遇到了这个问题。 鉴于在以简单的方式解决这个问题方面缺乏进展(即在安装时设置应用程序版本的标志),我想出了一个现在应该可行的替代方案。 这是超级简单真的-只是做了helm fetch先用解压选项,然后helm package--app-version确实存在有标志,然后进行安装,当地图。

这并不理想,但helm list的最终结果是正确的,并且在 CI 服务器上执行此操作非常简单。 不过,希望--app-version可以在helm installhelm upgrade

#5492 中讨论的总结是,包装helm packagehelm install逻辑的命令将解决此问题中最初描述的用例。

换句话说,您可以通过运行以下命令来解决此问题:

$ helm package myapp --app-version 1.0.0
$ helm install myapp-1.0.0.tgz

(将最近关闭的 PR 的评论移到这里 - 所以它不会最终进入 Nirvana)

这是我的 2 美分:
假设我们有一个掌舵chart version X使用appVersion Y部署服务。

helm chart 用于描述chart version X上 Kubernetes 内部的基础设施,用于托管appVersion Y

在初始开发期间, XY都会定期更改。 然而,在某些时候X或多或少会稳定,Y将继续变化(除非Y对基础设施有一些新的要求,这很可能很少发生在Y的开发周期中)。

使用这张票中提出的方法,可以在X版本上采用稳定的 helm chart 包来部署 appVersion YY+1Y+N等。

但是,不允许在 helm 安装或升级期间覆盖此标志,而仅在 eg 包中将有效地将XY在一起,迫使我总是创建一个新的X+1Y+1 。 这对我来说似乎没有必要,并且会导致大量 helm 包实际上没有改变,除了它们引用了一个新的appVersion 。 从我的角度来看,一个应用程序版本和一个托管该应用程序的基础设施版本有关系,但应该或仍然可以独立进行版本控制。 如何完成应该留给各自的开发团队。

概括:

这种方法确实有效,但也会导致很多不必要的 Helm 包,其中只有AppVersion发生了变化:
$ helm package myapp --app-version 1.0.0 $ helm install myapp-1.0.0.tgz

是的,但我想如果你采用我上面提到的方法,这不是什么大问题。 将您的图表推送到没有设置应用程序版本(或 0.0.0 或其他)的图表存储库,然后当您想使用它时,使用helm fetch ,然后将其与正确的应用程序版本打包,然后使用本地.tgz文件,不要推送该图表。 这样你的图表仓库就会保持干净,你只在那里展示了实际的图表变化。

是的,它会起作用。 在这种情况下,永远不能直接使用部署工件(例如,通过直接从 Helm 存储库安装),但总是必须通过一个额外的步骤来发送它,该步骤会改变工件。

有人认为Charts.yaml应该是不可变的,我认为部署工件应该是。

_总结我的想法来自https://github.com/helm/helm/pull/5492#issuecomment -520029902_

社区如何解释包、图表和版本存在问题。 @BenjaminSchiborr ,我希望这对你有意义。

图表- 是您发布的源代码。 就像您的应用程序的源代码一样。 由模板、代码文件组成。
- 是您发布的构建版本,工件。 就像从源代码构建的二进制文件。 由固定的生产版本组成:图表版本和应用程序版本。
发布- 是一个构建,使用指定的配置进行部署。

您无法从 Chart 中创建 Release 。 它只是不能这样工作!

在舞台上部署您的应用程序之前,您需要有一个图表。 然后,您需要使用图表打包您的应用程序,使用helm package修复两个版本。 它将产生一个包,可在任何阶段部署。 然后,您将此包安装到例如 QA 阶段,在 UA 上进行推广,然后在生产中使用helm install推广。

这是任何面向包的软件的工作方式。

混乱

helm install需要一个源,应该安装。 来源可能是:

  1. 包名,可从注册表获得
  2. 包文件路径,如果包已经下载或创建
  3. 包 URL,如果使用 HTTP 可用
  4. 图表目录路径

第 4 种方法在这里感觉就像一只害群之马,你不觉得吗? 这就是 ppl 混淆 Package 和 Chart 的原因。 这是问题的根源。

推理

有两种类型的应用程序:

大/中- 在这里,我们有时间、金钱和资源来设置详细的、细粒度的流程,以实现更好的内省和质量保证。
小型- 微服务、宠物项目、PoC、低成本项目、没有 DevOps 知识的项目,甚至是掌舵开发过程测试。

对于小型项目,您没有时间或需要创建或处理包装。 您想编写一些模板文件并使用一个命令部署它

这就是helm install允许这种用法的原因,如helm package & helm install 。 但它不提供完整的helm package功能,例如--app-version

helm install可以是helm package & helm install ,但它会使helm install变得一团糟,成为支持、测试和良好实践的地狱。

建议1

简化helm install 。 它应该只允许提供包,以简化代码库、测试并使其自以为是,以简化对helm理解。

提案 2 - helm run

引入新命令: helm run 。 一个命令,应该可以正常工作。 非常适合小型应用程序。 或者甚至可能是中型和大型。

它应该结合helm packagehelm install ,提供两个命令的功能,不包括在这种用例中没有意义的功能。

helm package创建一个构建,就像go build那样。 go run允许在没有构建过程的情况下启动应用程序,因此helm run在这里看起来像一个可靠的名称。

需要考虑的其他事项:

  • 它应该使用upgrade --install代替吗?
  • 它应该默认启用--atomic吗?

@iorlas ,
你的评论是有道理的。 但是,您假设只能有一个最终包将基础架构版本和软件版本继承地联系在一起,而我假设我有一个用于我的软件版本的包和一个用于我的基础架构的包,并且想要将它们捆绑起来在发布中(例如,通过引用软件版本和基础架构版本的所需状态配置)。

我不明白为什么应该将开发过程强制采用这种模式,在这种模式下,也可以由负责的开发团队决定是否要将基础架构和软件版本在 helm 包级别或更高版本绑定在一起。 当前,部署过程必须始终使用新的 helm 包,而仅更改软件版本。 这导致我的存储库中有数千个无用的包。

如果这有一些长期优势,我很好。 我只是没有看到。

@BenjaminSchiborr好吧,让我把它分解一下。

您可以拥有 Chart(== 基础设施),其版本X
您可以拥有您的应用程序版本Y

helm现在如何工作,它在helm package步骤将基础架构和应用程序版本联系在一起。 然后,您需要将其与 k8s 命名空间绑定,生成 Release。

所以公式是: package(infra + app) + k8s = Release

您真正想要的是跳过这个中间步骤,将所有 3 个组件在一个步骤中结合在一起 - 发布。 像这样: infra + app + k8s = Release 。 我对么?

从表面上看,这就是helm run会做的事情。 在引擎盖下,它会是一样的。

但是……我觉得你可能没看懂 Helm 的重点。 尽管任何工具都可以根据用户的喜好使用,但总有一个想法可以影响社区,创造一种“方式”,因此望远镜最终不会成为能够酿造啤酒的悍马。

让我试着描述它应该如何使用,从你的角度来看它会很棒。

Helm 本身的创建是为了抽象出 k8s 模板和部署,将应用程序和基础设施及其依赖关系联系在一起:而不是手动重写模板,将其应用于 K8s 然后提供新的图像标签,您只需要一个命令 - helm upgrade 。 就像一个 MSI 或 deb 包。

当您需要安装新的应用程序版本或将其降级时,您应该使用 helm。 您无需管理应用程序,而是管理整个程序包。 当出现问题时,单独回滚应用程序版本和基础设施会很痛苦 - 我去过那里,不会向任何人建议。

所以在你的注册表中有很多包是正确的,因为包不是基础设施,包是应用程序,因为应用程序在没有基础设施的 K8s 中并不意味着什么。

如果您的问题是存储库中有太多包,我建议您使用工件而不是存储库。 我在 CI 中这样做:构建应用程序,发送到 docker 注册表,创建包,将其保存为工件以供发布。 CircleCI、Travis、Azure Pipelines 支持创建附加的文件以构建为工件。 你也可以这样做吗?

也许我错过了 Helm 的重点。 也许 Helm 在这里遗漏了一点。 我认为这张票是关于评估的。 和个人 - 也是关于扩大我的视野:)

但是,是的,以抽象的方式,您所说的是正确的。 我不希望软件版本与 helm 包/发行版耦合,所以本质上它是infra + app + k8s = Release 。 与我不希望我的软件版本的属性绑定到我的 helm 包/发布(除了我可以覆盖的可能理智的默认值)一样。

关于您进一步提供的示例。 我不明白这如何表明这种方法是有问题的。 您仍然会使用 helm 来回滚或前滚。 如果基础架构发生变化,您将使用更改后的掌舵图版本。 如果软件版本发生变化,请使用不同的应用程序版本。 如果参数更改,则使用不同的参数。 每个服务总是(单个)掌舵调用。

能详细说说吗?

如果您的问题是存储库中有太多包,我建议您使用工件而不是存储库。

我指的是太多打包的舵图(已经包含 appVersion)。 可以将其视为一个稳定的 helm chart 版本和一个每天更改数百次的 appVersion。 因此,每天在存储库中为每个服务打包数百个掌舵图表,稍后由自动化使用。

(我的管道通常与您的相同:构建应用程序 --> Docker 映像(结果为 appVersion) --> 包图表(带有更新的 appVersion ) --> 推送到存储库?

我认为这张票是关于评估的。

一定! 在我看来,我们已经有太多的抽象层次,所以这里有一个 helm 有点不知所措😄此外,这里有 k8s 操作符,它们是为 Helm 解决的一些(也许是大多数?)问题而创建的。 不过那是另外一个话题了,嘿嘿。

可以将其视为一个稳定的 helm chart 版本和一个每天更改数百次的 appVersion。 因此,每天在存储库中为每个服务打包数百个掌舵图表,稍后由自动化使用。

是的,这绝对感觉太多了,但它是有意的。 比如,你有一个构建运行,它应该产生一些工件,然后保存它以用于在舞台上部署。 就像......我们怎么能有一个没有构建结果的构建运行? 我们应该在部署时生成构建吗? 这真的是错误的。 尽管一些 CI 管道会为 JS 构建做到这一点。

我们在 docker 上遇到了同样的问题:每次构建都会生成新的 docker 镜像,这些镜像会进入 docker 注册表。 我们需要保存它,如果我们没有它,我们应该如何部署它?

当然,我们可以docker save来节省注册表上的空间,并在稍后的构建工件保留策略中进行扫描。 但是我们可以helm package它保存为一个文件。

但我绝对明白你的意思,我们可以有一个“安装程序”,它可以接受一个应用程序版本。 由于此类安装程序具有基础结构,您可以保持不变,只需更改应用程序版本即可。 看起来整洁简单,但有一个问题。

应用程序本身在没有基础设施的 k8s 环境中没有意义

如果您的应用程序依赖于某些基础设施怎么办? 基本示例 - configmap。

如果您需要回滚应用程序怎么办?
您需要降级应用程序,但随后也需要降级基础设施。

如果您需要回滚基础设施怎么办?
以前的基础设施不知道您需要安装哪个应用程序版本,因为它与它无关。 因此,您需要记住哪个应用程序支持哪个基础设施并手动设置。

真的,那将是一个地狱。 当你没有掌舵时,现在就是地狱。 这没有错。 但在这种情况下,您几乎没有理由使用 helm。

我们已经有太多的抽象层次
一切美好而简单的眨眼

我认为你的最后一点很有说服力:

以前的基础设施不知道您需要安装哪个应用程序版本,因为它与它无关
如果你将这些东西解耦并且将 Helm 包/发布作为事实来源,这绝对是一个问题。

然而,对于许多人来说,情况可能并非如此。 Helm 之上有一个编排(是的,另一层抽象),它将多个舵图(和应用程序版本)联系在一起(想想舵手、线束等)。 并且该层本身也是版本化的。 在这种情况下,您所描述的不再是问题,因为您不会恢复到旧版本的掌舵图,而是恢复到旧版本的编排层(这对应用程序和基础设施有意义)。

但是单独掌舵,是的,100% 是个问题💣。 我认为这就是为什么这个想法是明确允许覆盖 appVersion 并且默认情况下不允许它的原因。

我喜欢将图表版本和应用程序版本结合在一起的一件事是,哪个应用程序版本属于哪个图表变得很清楚。 如果您需要重新部署一个特定版本,则不必记住哪个应用程序版本与哪个图表版本兼容。 因为它们链接在一起,所以您只需参考正确的图表版本,您就可以确定该应用程序和图表匹配。 我认为这基本上就是@iorlas所描述的,对吗?

最后,图表版本将充当“超级”版本:

  • 任何更改(无论是否更改了应用程序或基础架构,即图表)都将产生新的图表版本,即新的应用程序版本将意味着图表版本也发生了变化
  • 新的图表版本并不意味着应用程序版本已更改

出于文档目的(也许还有其他奇特的想法),您可以自己引入另一个“仅图表”版本,该版本仅指图表定义本身。

@filipre
对对对! 根据当前的架构设计决策,这就是 Helm 应该如何工作。 照我看来。

问题是有时感觉很奇怪 - 设置太多,而且将应用程序和基础设施捆绑在一起的想法令人怀疑。 那么,这是正确的方法吗 - 这是一个问题。

@BenjaminSchiborr

然而,对于许多人来说,情况可能并非如此

一定! 即使是整个 k8s,容器化也可能太多了。

让我试着从另一个角度分解它,试图找出 helm 的问题:

  • 基础设施实例是整个产品的工作原理:SaaS 实例、VM 池、k8s 设置、应用程序版本(包括数据库、可观察性工具、路由器、sidecar 和产品应用程序实例)
  • 基础设施实例需要一个事实来源。 现在我们有了像 Terraform 这样的实用程序。
  • 一个文件夹中有太多东西=很难。 我们需要分解它。 你好 Terraform 模块。
  • 一个文件夹中的平台和应用程序 = 难。 我们需要分解。 你好平台和容器。 K8s 介入。

    1. 因此,Terraform模块可以管理平台,包括创建空的、随时可用的容器层

    2. K8s管理容器,允许使用 YAML 创建基本资源

  • 许多 K8s 应用程序(包括数据库和东西)的许多YAML 文件= 很难。 将其拆分为每个应用程序的文件夹。

    1. 所以我们有一些文件夹,如 PostgreSQL、Redis、MyPetShop。 每个都有我们拥有的资源的 YAML 文件。 它需要设置其应用程序版本才能应用于 K8s。

  • 你好Helm - 工具,它允许设置这些文件夹(称为图表),但更多:将它们一起应用,回滚。
  • 图表看起来很稳固。 让我们通过支持变量来重用它。 现在 Chart 不是基础设施,而是基础设施模板。
  • 图表看起来很棒。 让我们与朋友分享。 每次更新图表时,我们都需要将其推送到带有 index.html 的文件 repo 中。

所以,感觉棒极了,完全没有包。 因此,您需要应用此图表,然后提供应用程序版本。 应该是这样。

但是问题出现了:没有人想记住哪个应用程序版本需要哪个图表。 更新哪个图表以提供哪个应用程序版本的新配置值。

归根结底,我们想要的只是“将 myApp 版本 1.4.2 设置为 K8s 应用程序” ,它将所有风险、依赖项、更改封装到一个工件 - 应用程序安装程序中,即apps versions + hooks + setup logic + infrastructure to connect it all 。 这就是为什么我们有 MSI、Deb、RPM,甚至 NPM、Go mod、Pip、Gem 之类的东西。

这就是Package出现的地方。 根据定义,Package 需要在 CI/CD 流程中创建为可安装版本。 所以我们可以将它发送到我们系统(k8s 集群)上的注册表和/或设置中。

没有其他项目是不同的。 当我们直接helm install Chart 时,没有包,我们做同样的事情。 但是我们不是创建包,而是在不同的步骤中创建它。 我们不是在应用程序构建过程中构建它,而是在发布步骤中构建它。 我们仍然将基础设施和应用程序版本联系在一起含蓄地

有趣的是:

  • 依赖更新 = 更新基础架构模板(图表)版本
  • 应用更新 = 生成一个分支,基础架构模板的子集(图表)- 包,有自己的版本

尽管如此,k8s 算子还是要针对当前的问题,所以应该只有一种工具,它应该像算子一样工作,但提供简单的发布过程,就像 helm 一样。

有什么想法吗? 我们可能会在这里创造一些新的东西,但更好

您所描述的内容对于旨在供其他人在您无法控制的基础设施上使用的应用程序很有意义。 然而,在企业场景中,制作包变得繁忙:我们可能有几十个千篇一律的微服务,它们被部署到共享或千篇一律的环境中,并且凭借存在于 repo 本身中的 CI/CD 管道定义(想想azure-pipelines.yaml),“包版本”只是从主分支的特定版本生成的构建。 意思是,我真的不需要将“包”存储在任何地方 - 我的构建将生成相同的包,在配置映射等中使用相同的位和相同的变量。在这样的场景中,我只会在服务基础设施发生变化,这种情况很少发生。 Helm 出现在这张照片中是因为 1)我已经必须使用它来部署一些基础设施(例如,nginx),2)我不必使用模板 k8s yaml 重新发明轮子。

@wasker

例如,让我们将其投影到 docker 上。 Docker 镜像也是一个包。 它将二进制文件与操作系统映像 = 基础设施联系在一起。 我相信,每次构建时都要制作 docker 镜像的原因,与制作 helm 包的原因是一样的。

如果不需要将所有内容抽象为 docker 镜像,则不需要 docker 并且可以使用普通 VM。

因此,如果我们尝试将 docker 的使用情况投射到 helm 上,那么仅使用 helm 作为基础设施工具就像仅使用 docker 创建初始映像,然后通过发送新的二进制文件在 k8s 主机本身上更新此类映像。 这很糟糕,就像使用 helm 而不是每次都重新打包一样糟糕。

不管怎样,我想,我们走错了路。 有没有人使用 helm 然后手动更新图像? 我相信,我们有 3 个一般用例:

  1. helm package chart -> helm install package
  2. helm install chart
  3. helm install -> kubectl set image

@wasker哪一个是你的? 我相信,不是第三个。 即使它是基础设施配置和应用程序版本控制的真正分离,使用起来也会很讨厌。 因为,这意味着,当您需要更新基础架构时,您将丢失所有版本。 您需要在 Chart 中、手动或kubectl set image为每个部署更新它。

所以,我们谈论的是第二个, helm install chart ,“没有包装”。 所以,掌舵总是在画面中。 问题是,包是构建的,但是在运行时 - 当我们部署我们的应用程序时。 因此,当我们需要部署它时,CI 构建会隐式地负责包的创建。

如果在 golang 上进行项目,这种做法看起来就像发送源代码并在 docker 中以go run运行它,而不是构建它并使用二进制文件。

因此,跳过封装步骤简化整个画面。 吗?

这是我们可以开始谈话的地方。 这里https://github.com/helm/helm/issues/3555#issuecomment -529022699 是我的建议。 添加helm run并将其建模为go run

如果我们真的需要拆分基础架构和应用版本控制,那就意味着只使用 helm 来更新/播种到基础架构。 即使我想看到一种这样做的方法,我也可以看到一种方法,它不会增加更新的麻烦。 我们可以忽略当前的部署版本和其他东西……但我觉得这是错误的,创建它会浪费时间。

例如,让我们将其投影到 docker 上。 Docker 镜像也是一个包。 它将二进制文件与操作系统映像 = 基础设施联系在一起。 我相信,每次构建时都要制作 docker 镜像的原因,与制作 helm 包的原因是一样的。

我想问题在于,如果您正在制作新的 Docker 映像,那是因为该映像中的某些内容已更改。 在此处描述的场景中,打包的 Helm Chart 的内容没有改变,除了一行 - 应用程序版本。 这确实会影响最终结果,但不会改变 Helm 图表本身的行为方式。 它将以相同的方式做同样的事情,只是使用不同的值——作为一个实体的 Helm Chart 并没有因为应用程序版本的变化而发生丝毫变化; 只有在它结束时释放的东西才有。

您可以在这里与使用 Docker 映像配置等功能进行比较。 您将环境变量传递给 Docker 映像,这会影响它在运行时的运行方式,并且您不会重建映像来更改这些变量。 图像的内容没有改变,但最终结果有 - 那里的情况非常相似,但在这种情况下,行为是可取的和正常的。

如果将其投影到 golang 上,这种做法看起来就像发送源代码并在 docker 中以 go run 的方式运行它,而不是构建它并使用二进制文件。 [...] 因此,跳过封装步骤的真正原因是为工程师简化整个画面。 是吗?

在我看来不是。 实际上,这里的论点是人们是否考虑应用程序版本“图表的一部分”,以及他们是否认为 Helm Chart 与作为图表结果部署的 Docker 镜像不同。 我对此的看法就是我上面提到的。 这就像在 Docker 镜像中获取编译好的 Go 二进制文件,并使用一些不同的环境变量运行它。

话虽如此,关于使用新的应用程序版本重新打包 Helm Chart 并使用 Chart 版本作为某种“超级版本”的论点是引人注目的(即始终拥有一个兼容的应用程序版本的优势)图表 - 前提是应用程序版本不能通过值自定义)。

我的问题是 - _为什么不支持这两种方法?_ 每种方法都有优点和缺点。 从根本上说,不支持这只会使一些完全有效的工作流程变得更加困难。 例如,使用 Flux CD 和 Helm Operator。 如果你有一个共享的 Helm Chart(即因为你有某种类型的服务,你部署了很多并且它们共享许多相同的特征),那么为了获得有用的helm list输出,你必须有一个新的 Helm每个应用程序的图表,每个版本也需要它自己的 Helm Chart。 仅此一项就使管道复杂化,因为如果 Chart 可以共享,它可以拥有自己的管道,仅在更新 Chart 时运行,并且应用程序管道甚至不需要运行单个 Helm 命令(如果 Flux CD 添加了对安装/升级时的新应用程序版本标志)。

我的问题是 - 为什么不支持这两种方法?

这正是我的想法。

就我而言,“超级版本”不是掌舵图,而是仅使用过多掌舵图的另一层。 对我来说,单个 Helm 图表毫无意义,因为它只描述了许多其他服务中的一个小服务。 只有在一起才能形成有意义的释放。
因此,在我的情况下,“超级版本”是所有这些版本的汇总(这就是实际版本控制的方式)。

尽管如此,将 Helm 图表本身作为描述性的“超级版本”仍存在争议。

回到@seeruk的观点:为什么不支持两者?

获得外界的声音可能对当前的辩论有所帮助。 对于一些上下文,我一直在使用helm总共 _11 天。_ 我认为这给了我一个独特的视角来补充,因为我没有参与任何高级学习。 我收集到的一切都来自文档和实验。

我如何看待 Helm

在阅读有关 helm 安装而不是图表的当前辩论之前,我一直认为 Helm 主要是用于描述相关 Kubernetes 资源的接口。 这种信念主要来自 Helm 文档,它说:

Helm 将图表安装到 Kubernetes 中,为每个安装创建一个新版本。 要查找新图表,您可以搜索 Helm 图表存储库。

对于上下文,当前稳定的 helm 文档还指出:

Chart 是一个 Helm 包。 它包含在 Kubernetes 集群内运行应用程序、工具或服务所需的所有资源定义。 把它想象成 Kubernetes 等价于 Homebrew 公式、Apt dpkg 或 Yum RPM 文件。

所以现在有些混乱! Helm 文档清楚地说明“图表是一个 helm 包”,但如果是这样,那么为什么helm install接受非打包的 Chart 存储库?

正是这种行为影响了我目前对掌舵是什么以及它应该如何工作的看法:

Helm 在进入集群的_what_ 的结构和这些东西具有的_what 属性之间充当映射器。

所以现在的问题是:“Helm 正在部署什么?”

什么是 Helm 部署?

当我运行helm install release-name ./local_chart我希望 helm 使用指定的值(通过默认值或覆盖)在本地呈现所有图表模板,并将呈现的版本推送到 Kubernetes。 我还希望 Helm 在我回滚时保留之前部署的 Kubernetes 对象。 这个“渲染模板集合”(包含一些元数据)的概念一个版本,一个包。 所有这些资源定义(即使它们没有改变)都需要处于_它们在包中描述的状态_才能使版本存在(或回滚到)。

由此,我推测 helm只会真正部署包。 这似乎是你能说的唯一语义正确的东西; 然而,关于这些包如何分发的争论似乎是实践中这场争论的根本原因。 具体来说,“升级或更改应用程序版本是否构成新包?”

根据_我的个人语义_,这个问题的答案是肯定的。 根据除非某些内容发生变化,否则您不会更改版本号的论点,如果某些基础属性发生变化,您只需要调整应用程序的版本号。 这可能涉及从注册表中提取不同的 docker 映像,或通过环境变量设置功能标志,或可用于更改某些代码工件行为的任意数量的不同实践。

正因为如此,我开始清理我们的注册表,除了在开发中之外,从不从:latest部署。 使用“元标签”而不是来自 docker 镜像的发布标签使得将给定的部署绑定到给定的代码库变得不可能。 我们以艰难的方式学习了这一点(但幸运的是在测试中,而不是在生产中)。

应该使用哪种模式?

这已经被 Helm 认为是: packages

鉴于此模式是强制模式,即使它不是 100% 明显,提供--appVersion标志似乎在逻辑上是一致的。 回答这个问题的“为什么”可能比其他任何事情都重要,所以让我用这个答案结束我的贡献。

为什么支持--appVersion?

我们来看一个特殊的部署案例:

一家公司有一个应用程序有两个主要版本。 该公司的一些客户尚未承诺升级到此应用程序的最新主要版本,而是使用两者中较旧的版本。 由于付费开发合同,现场开发仍然在旧的主要版本上进行……但产品是“相同的”。 为这个应用程序的两个版本部署的基础设施是相同的; 但是,这些部署之间的应用程序版本将大不相同。

这家公司要做什么?

  1. 制作两个独立的、几乎相同的舵图,它们仅在appVersion有所不同?
  2. 使用一个舵图但不断更新appVersion在主要应用程序版本之间来回切换?
  3. 使用标志(当前不受支持)覆盖appVersion导致命令行上的潜在开发人员错误?
  4. appVersionChart.yamlvalues.yaml

提案 1 引入了比其他提案略多的开销,但如果这些应用程序版本出现分歧,则还具有将这些应用程序版本的图表分开的好处。 它有一个明确的用例,可能会在这个问题的许多情况下被采用。

提案 2 的开销比提案 1 少,但在图表中引入了高可变性。 如果您去运行helm install release-name https://remote-repo.com/chart并且图表的最新版本是应用程序的错误版本,会发生什么情况? 哎呀。 可能不是最好的方法。

提案 3 是我们目前正在讨论的内容。 我个人不喜欢这个选项,但只是因为我觉得这是解决问题的错误方法。 它是否使 appVersion 可配置? 当然。 但它也有与您在运行helm install release-name https://remote-repo/chart时遇到的相同问题:元数据是短暂的,仅由 Helm 维护。

我真的很震惊,没有人提供提案 4 或类似的东西。 它将 appVersion 置于可以被覆盖的状态(启用类似于helm run ),可以包含在helm package生成的包中,并真正解开应用程序版本的概念从图表版本开始,同时保持appVersion与 helm 部署耦合的概念(appVersion 必须在某个地方,对吗?)。

我希望这是有帮助的。 👀这个公关。

@jrkarnes :从某种意义上说 4) 已经被提出并被许多人用作解决方法(参见此处 https://github.com/helm/helm/pull/5492#issuecomment-517255692)。 你可以在你的图表模板中使用这样的东西:

{{ default .Values.appVersion .Chart.AppVersion }}

这将允许您使用appVersion中的Charts.yaml作为默认值,并使用Values.yaml中的内容覆盖它(可以在安装/升级调用期间覆盖)。 不利的一面是,在执行例如helm ls它会向您显示没有或不正确的appVersion

@BenjaminSchiborr感谢您让我知道这一点。 正如我所说,我进入helm工作区的时间非常有限,因此对我来说,此时任何知识都是很好的知识

我认为我的第四个建议有点被误解了。 而不是像{{ default .Values.appVersion .Chart.AppVersion}}这样的东西,你会使用{{ .Values.Helm.AppVersion}}并且values.yaml持有appVersion而不是Chart.yaml

@jrkarnes
这就是我现在的想法。 比如,为什么应用程序版本应该被视为 uniq 雪花。 这是图表的价值。

这背后的推理很简单:一切都是基础设施的一部分。 所以,infra 有版本。 为什么有两个版本?

但我太忙了,无暇顾及侧箱和投影。 但总的来说,这是一个问题:为什么我们需要应用程序版本,简而言之,它是所有基础设施? 或者当 Chart 仅是基础架构模板时,我们可以使用图表版本作为基础架构版本,而当基础架构包含应用程序版本时,我们可以将其用作应用程序版本吗?

我会再考虑一下

@jrkarnes
这就是我现在的想法。 比如,为什么应用程序版本应该被视为 uniq 雪花。 这是图表的价值。

这背后的推理很简单:一切都是基础设施的一部分。 所以,infra 有版本。 为什么有两个版本?

从根本上说,将图表版本与应用程序版本分开是有意义的。 一个简单的例子可能是证明这种情况的最好方法。

假设您部署了一个ver 4.0.0应用程序,该应用程序在您的图表版本化ver 1.1.0 。 在您的操作过程中,您意识到您将需要开始为此应用程序运行 cron 任务。 您没有编写 cronJob 对象并将其应用于集群,而是意识到运行此图表的其他人可能也需要 cron 任务……因此您将其添加到您的图表中。 您的图表现在已经发展到ver 1.2.0但图表管理的应用程序没有发生任何变化,它仍然是ver 4.0.0

反之亦然也适用,并且已经是本 PR 中的辩论主题。

但我太忙了,无暇顾及侧箱和投影。 但总的来说,这是一个问题:为什么我们需要应用程序版本,简而言之,它是所有基础设施? 或者当 Chart 仅是基础架构模板时,我们可以使用图表版本作为基础架构版本,而当基础架构包含应用程序版本时,我们可以将其用作应用程序版本吗?

我会再考虑一下

与其考虑附带案例或投影,不如想想 MySql 之类的东西,它具有三个广泛使用和支持的引擎版本: [5.6, 5.7, 8.0] 。 要将mysql实例部署到集群中,您将始终拥有:

  • 运行所选版本的 MySql 实例的 Pod
  • 一个服务,允许 kube-dns 解析到 pod(或 pod,如果在 HA 中运行)
  • Pod 将数据写入的 PV 以及随附的 PVC

部署 MySql 5.6、5.7 或 8.0 的图表对于所有引擎(应用程序)版本应该是

我明白你想知道应用程序版本的“需求”是什么意思。 我认为这归结为运行helm lshelm inspect时开发人员或操作的便利性。

+1 到@jrkarnes 的最后一个帖子。 正是因为图表版本是“基础设施版本”,因此将图表和应用程序版本作为单独的概念保留有很多价值。

如果我发布图表供其他人使用,它就会成为依赖它的项目的基础架构的一部分。 但是,如果我从不打算让我的应用程序被其他人使用,那么我所关心的就是不时修改我自己的图表版本,helm install last-known-good-chart-version回滚我的部署,而是简单地使用指针重新运行我的 CD 管道到最后一个已知的良好提交 ID。

@iorlas我已经阅读了你对helm run提议,我对此没有任何问题。 虽然我认为没有必要进行安装/运行二分法,但如果它让掌舵维护者放心让应用程序版本可变,我就可以了。 :)

@iorlas你有没有机会考虑一下你想用这个提案做什么?

我不认为我理解涉及{{ default .Values.appVersion .Chart.AppVersion}}的变通函数。 我收到此错误:

错误:将 YAML 转换为 JSON 时出错:yaml:无效的映射键:map[interface {}]interface {}{".Values.appVersion | default \"0.0.1\"":interface {}(nil)}[

这是我的 Chart.yaml:

name: demo-helm
version: 0.0.1
appVersion: {{ .Values.appVersion | default "0.0.1" }}
home: http://example.com
description: Demo Helm

@IRobL您需要将此代码段放入templates/deployment.yaml ,其中使用了 version。 像values.yaml这样的文件不被视为模板。

@jrkarnes我不是维护者,所以我猜最终决定权在其他人helm及其packages

我们使用我描述的方法:

  • Helm Chart是应用程序存储库的一部分
  • 应用程序构建产生:

    • Docker 镜像 -> docker 注册表

    • 静态文件 -> CDN 服务

    • Helm 包 -> CI 存储

  • 所以,Helm 包是主神器,将所有应用程序神器绑定在一起
  • 在部署时, install表示包

目前的顾虑:

  • 构建过程的复杂性。

    • 生成附加文件( helm package )而不是 docker 图像和静态文件

    • 除了go build / make install结果文件之外,我们需要任何东西的主要原因是什么?

    • 费用是多少?

    • 为什么要申请?

    • 什么时候申请?

  • 构建持续时间

    • 即使我们不需要部署它,我们仍然会浪费一些时间和金钱。 2-5 秒。 不多,但无意义的工作是没有意义的。

  • 基础设施模板更新的复杂性

    • 当图表更新时,值也应该更新

    • Chart 是一个 repo,values 是另一个,每次更新值都意味着有点头疼

这种重新评估可能会导致更多的简化和想法。 走着瞧 :)
我会在接近下周五的时候发送更新。

啊,我明白为什么现在你为我指出了这一点,这个技巧不起作用,谢谢。 这里有一个技巧,我认为对于使用 Helm 2.x 的许多人来说效果很好,假设您可以轻松地用这些类型的头顶部件包裹您的掌舵工具:

APP_VERSION=0.0.7
sed -i.bak "s/^appVersion:.*\\\$/appVersion: $APP_VERSION/" helm/Chart.yaml
helm install --name helm_demo helm/

@IRobL

通常,如果您使用 sed 包装部署,则意味着模板引擎没有按照您的需要执行操作,这就是本次讨论的重点。

当 gitlab 还处于起步阶段并且没有 helm 支持时,我们实际上是在手工制作的清单文件中输入替换目标的值。

对于这样的事情,这是一种不好的做法,如果可能的话,我会敦促您远离它。

2019 年 10 月 7 日下午 3:33,IRobL [email protected]写道:

啊,我明白为什么现在你为我指出了这一点,这个技巧不起作用,谢谢。 这里有一个技巧,我认为对于使用 Helm 2.x 的许多人来说效果很好,假设您可以轻松地用这些类型的头顶部件包裹您的掌舵工具:

APP_VERSION=0.0.7
sed -i.bak "s/^a ppVersion:. *\\$/appVersion: $APP_VERSION/" helm/Chart.yaml
helm install --name helm_demo helm/

你收到这个是因为你被提到了。
直接回复此邮件,在 GitHub 上查看,或将线程静音。

@jrkarnes ,当你说不好的做法时,你是说需要用脚本包装helm命令是不可取的吗? 如果是这样,那么我完全同意。 我并不是说我完全反对添加--app-version标志; 相反,我认为这对 helm 来说是一个非常方便的补充。 很明显,基于这个 PR,我并不是唯一一个想要让 appVersion 变量与正在部署的实际构建保持一致的 helm 人。 我碰巧正在开发一个可重复使用的构建管道库,它将各种构建工具包装在一起以生成可重复的构建——这是大型技术组织的常见做法。 在我的用例中,管道库构建 docker 容器,发布它们,并最终通过应用程序构建管道中的 helm 部署它们(例如,考虑应用程序版本1.0.1-pr-3.1用于第三个 PR 的第一次构建一个应用程序,它可能是 1.0.1 版的预发布)。

即使在我公司的构建管道库中解决了这个问题之后,我肯定会觉得在 Helm 中内置一个--app-version开关会更舒服; 它只是感觉像是一种更灵活的部署方式。 我的意思是,如果外部系统或工程师必须在每次部署之前进入 Chart 文件并更新 yaml,如果它可以由一个不会意外弄乱数字的构建平台自动化? 从我的角度来看,我的组织需要完全放弃 appVersion 功能,或者需要将“草率” sed解决方法添加到我们的管道库代码中,所以我想我会分享它解决这个问题的任何其他人。

@IRobL
一般来说,任何实用程序都应该在自己的抽象级别上自给自足:它应该通过提供足够的 API 来抽象出它解决的问题。 头盔也不例外。 因此,如果您需要自定义它的行为方式,您首先需要质疑:它是否符合架构、设计原则,或者我是否遗漏了什么?

这就是为什么这个 PR 没有那么容易解决的原因。 因为,修复是显而易见的,但它不符合 Helm 设计。 这就是为什么很少提供临时解决方案的原因。

你是对的app-version标志。 你应该提供它,然后 Helm 应该自己处理所有事情。

我可以问你一个问题吗? 你如何在你的产品中使用 Helm? 当您使用helm install ? 你具体是怎么用的? 您是否考虑过使用helm package

昨晚我又看了一遍helm package 。 我真的没有被卖掉。 sed已经存在很长时间并且非常稳定。 所有这些tiller / package / install子命令都相对较新,稳定性较差。 为了帮助阐明我的观点,几个月前,即使我看到有人的插件绕过了对 Tiller 的需求,我还是决定“确定 Tiller 可以工作”。 我认为该插件肯定不那么主流,但从那以后我一直在踢自己。 如果我信任这个插件,我的处境会比现在好得多。 Helm 的维护人员甚至确认他们同意这是一个无法维护的设计,它将在未来的版本中消失。

我认为使用helm package来执行这些简单的 sed 操作是我的错误。 无论如何,您对package的用例是什么? 我觉得helm package的整个概念似乎错过了 web 2.0/ 版本控制发布的重点,因为现代技术团队一直在利用标记的力量来实现相同的过程但以更精简、更易于审计的方式。

对于我的用例,我让应用程序开发人员能够编写他们的容器化应用程序并以可维护的方式部署它们,因此最大限度地减少开销(操作/分蘖系统管理员、冗余发布工件管理等)是最重要的。 我认为我的使用更接近于 Unix 哲学,决定使用一个工具来做它最擅长的事情,然后在适当的时候切换到其他工具(例如 sed)。 我认为您永远找不到一种工具可以完美地为您完成所有工作,但是如果您对当前的工作流程感到满意,请不要让我劝阻您遵循自己的理念。

@IRobL

当你说不好的做法时,你是说需要用脚本包装 helm 命令是不可取的吗?

是的。 这正是。

在我的用例中,管道库构建 docker 容器,发布它们,并最终通过应用程序构建管道中的 helm 部署它们

这也正是我们正在做的事情。

即使在我公司的构建管道库中解决了这个问题之后,我肯定会觉得在 Helm 中内置一个 --app-version 开关会更舒服

我会更进一步说,让appVersion成为Chart.yaml文件的一个属性可能是不正确的。 如果该值可以即时更改,则它不应该位于所谓的“不可变值集”中。 我相信我在之前的评论中主张同样的事情。

所有这些分蘖/包/安装子命令都是相对较新的,并且不太稳定。

FWIW, Tiller不会出现在 Helm 3 中。你在后面的帖子中提到了这一点; 但是,我只是重申这一点,因为它确实表明创建“kubernetes 二进制文件”并将其传送到Tillerhelm package语法可能是一种不好的做法。

我认为使用 helm 包来执行这些简单的 sed 操作是我的错误。 无论如何,您的包装用例是什么?

我可能会在这个问题上为 Helm 团队辩护。 我在掌舵之后的感觉是让应用程序开发人员指定如何从 Kubernetes 内部正确运行他们的应用程序的方法。 这就是应用程序提供商运行他们自己的 Helm 存储库的原因,您可以添加这些存储库以下载他们部署的给定版本。 Helm 团队可能认为应用程序代码和基础设施代码是相互交织的,因为他们预期的目标生产团队不会像我们在 CI/CD 中那样在日常工作流中使用 Helm。 示例:我们平均每天使用helm upgrade 130 次。 我认为这不是预期的用途。

人们说“我只是想将 mysql 安装到 kubernetes 中”可能更常见,而对于那些对 kubernetes 知之甚少并且只是玩弄它的人来说,helm 是一种(相对)简单的方法。

因此, helm package最终旨在被_那个观众_消费。 该工具肯定会在团队(我认为)不相信会选择该工具或从未打算以他们现在的方式使用它的领域中得到更多的使用。

我认为我的使用更接近于 Unix 哲学,决定使用一个工具来做它最擅长的事情,然后在适当的时候切换到其他工具(例如 sed)。

我基本上把 Helm 当作awk对待,后面有一堆kubectl apply -f 。 让自动化工具处理值以避免人为错误会更干净。

听起来你和我有很多相同的价值观,可能正在做很多类似的事情。

@IRobL

分蘖

对我来说, tiller是不可接受的。 由于它增加了一个暴露点,增加了额外的安全风险,最重要的是,它只创建了另一种应用 yaml 文件的方法,但具有不同的 API。 Tiller 旨在保护、调整 Helm 包的应用过程,但具有如此多的风险、额外的软件(和版本控制!)。 这就是 Helm the 3rd 不使用它的原因。

我认为使用 helm 包来执行这些简单的 sed 操作是我的错误。

我认为你没有抓住我的意思。 让我再试一遍。 sed做什么用的? 转换数据流。 它应该抽象出转换问题,为您提供任何给定输入的 API 和结果。

如果您编写了一个脚本,而您的sed命令不起作用(即您的正则表达式有误)怎么办? 所以你得出结论,它行不通。 你会试着理解为什么sed不能单独工作,还是你会用 perl 脚本添加一个额外的管道?

每个解决方案都是一样的:它应该提供 API,接受输入并提供输出,抽象出一个问题。 你知道,Unix 风格。

投射到 Helm 上,它旨在对您的版本进行版本控制并将其推送到 K8s。 它允许使用模板自定义配置。 所以,你正在观察一个问题,你需要提供一个版本。 Helm 提供了一种管理版本的简单机制,并提供了自定义构建工作方式的简单方法。 那么,为什么不尝试了解它的工作原理,而不是使用其他软件添加解决方法呢?

@jrkarnes

是的,我们都怀着相似的兴趣接近掌舵人。 我还没有真正意识到package命令的根源与分蘖铺平的错误交织在一起,感谢您与我分享这些见解!

我实际上正在回顾为什么不只是添加此功能的历史,并看到了关于为什么他们不能添加此功能的两个论点,一个是因为它已经在package定义,因此他们不应该也也必须在install / upgrade定义它。 我对此表示同情,这听起来像是技术债务问题。 没有技术债务的公开使用的软件是不存在的。 另一个原因是 Chart.yml 文件是元数据,不应更新。 这让我觉得很奇怪……当人们开发掌舵图时,他们肯定会随着事情的变化手动更新该文件,因此它本身并不是一成不变的。 我更容易将 Chart.yml 文件视为一种向 helm 二进制文件提供参数的方式,因为它构建了相比之下实际上不可变的部署对象。

顺便说一句,您的构建平台是什么? 我正在编写的管道代码是为 Jenkins 作为全局管道库编写的。

@IRobL关键问题是:您将 Helm 视为部署脚本。 但是 Helm 不是那样的。 Helm 是一个抽象层。 Helm 将您所有的工件作为一个工作单元应用到作为平台的 K8s 上。

Helm 是一个打包器。 Helm 旨在简化部署。 它从您的工件中创建“安装程序”,因此您可以将其“安装”到您的操作系统 - K8s 上。

app-versioninstall无关与科技的债务。 当您想要installupgrade时根本不需要它。 同样是Chart.yml 。 它根本不应更改,因为它是默认配置文件,其中包含实际 Chart 的版本,但 chart 不是您的软件。 你只是用错了。

从这个角度来看,你为什么不考虑使用package ? 对你来说看起来太复杂了还是什么?

在这个问题上已经有一段时间了,但我已经看到这种观点出现了几次:

Helm 是一个打包器。 Helm 旨在简化部署。 它从您的工件中创建“安装程序”,因此您可以将其“安装”到您的操作系统 - K8s 上。

从根本上说,Helm _不以任何方式_创建安装程序。 它不会创建“二进制”。 它不会创建类似于“.deb”文件或类似的东西。 它创建了一些 Kubernetes 清单模板的存档,其中包含一些默认和/或预设值。 您的实际软件并不存在于该 Helm Chart 中。 它没有与它打包。 它不能保证是不可变的。

我认为可以公平地说,在大多数情况下,您的 Helm Chart 将比您通过 Chart 部署的软件更改 _lot_ 少。

这是--app-versionhelm installhelm upgrade上可用的根本原因(至少是 IMO)。 如果实际上没有任何变化,为什么还要重新打包图表?

我将 Helm Chart 视为 Kubernetes 清单的版本描述,描述了一组将成功运行应用程序的 Kubernetes 组件,这就是我所看到的。 如果这些说明需要更改,那就是我想要更新我的图表的时候 - 不是每次我的应用程序更改时,我只需要更新图像版本(无论如何您通常都通过值设置)。

以 Flux 为例,看看他们的 Helm Operator 是如何工作的。 您可以让它自动更新图像标签值 - 这不会更新图表,只会更新正在部署的图像标签。

它创建了一些 Kubernetes 清单模板的存档,其中包含一些默认和/或预设值。

但是 deb 文件是同一组配置文件、命令、清单和/或预设值。 与MSI安装程序相同,甚至更接近于gentoemerge软件包系统中的ebuild。 此外,与 Brew 包相同。

那么如果不是 K8s 的包管理器,Helm 是什么? 你看到的区别是什么?

它不能保证是不可变的。

为什么不? 如果在包生成后对包进行变异,则是错误的。 如果您在install/upgrade过程中提供其他选项,则是有意为之,就像在所有包装系统中一样。

我将 Helm Chart 视为 Kubernetes 清单的版本描述

你已经有了一个 - GIT。 那么,为什么需要 Helm 呢?

我认为可以公平地说,在大多数情况下,与您通过 Chart 部署的软件相比,您的 Helm Chart 的变化要少得多。
这是 --app-version 可用于 helm install 和 helm upgrade 的根本原因(至少是 IMO)。 如果实际上没有任何变化,为什么还要重新打包图表?

在此设计中,不应将 appVersion 视为 Helm 包构建的属性。 它应该被视为配置参数,以值表示。

以 Flux 为例,看看他们的 Helm Operator 是如何工作的。 您可以让它自动更新图像标签值 - 这不会更新图表,只会更新正在部署的图像标签。

在这种情况下,您将松散应用基础架构清单和应用版本的耦合。 因为,更改图像标签不会触发新的 helm 升级(如果 Flux 人员以其他方式执行此操作,请纠正我)。 在这种情况下,您将使用 Helm 作为配置模板。 在这种情况下,您根本不需要--app-version

但是 deb 文件是同一组配置文件、命令、清单和/或预设值。 与MSI安装程序相同,甚至更接近于gentoemerge软件包系统中的ebuild。 此外,与 Brew 包相同。

您在此处对.deb.msi软件包的描述缺少一个关键组件 - 正在安装的实际内容。 如果您查看.deb文件的内容,您会发现构建的软件 - 将要安装的 _THE_ 软件。 一般来说(总是在.deb的情况下?)正在部署的应用程序是内在链接的,并且是该包的一部分(不是 brew 的情况)。

Brew 包是不同的,并不能以相同的方式进行比较。 不过,Brew 目前实际上更类似于 Helm,因为它只是关于如何安装它以及应从何处下载源/包的说明。

这里要绝对清楚; Helm Chart _与特定应用程序版本无关_,并且不包含正在部署的人工制品(即 Docker 映像)。 它只包含对它的引用,该引用背后的值甚至可以更改(即,如果您愿意,您可以推送到同一个 Docker 标签)。 所以无论如何,Helm Chart 不是应用程序的打包版本,也没有严格链接到应用程序的特定版本。

您只需要查看稳定图表存储库的示例即可。 有多少应用程序允许您通过值覆盖正在使用的图像? (很多_)

那么如果不是 K8s 的包管理器,Helm 是什么? 你看到的区别是什么?

它是一种工具,可用于对 Kubernetes 清单进行模板化,并轻松分发和安装它们。 这里的关键是,这就是 Helm 处理的所有内容——Kubernetes 清单。

这一切都回到了我的主要观点——如果这些清单发生了变化,或者出于某种原因需要为这些清单更改模板,那么 _that_ 就是真正需要更改 Helm Chart 的时候。

我看到的主要并发症是有 2 个用例:

  • 部署第三方应用程序。
  • 部署第一方应用程序。

对于第三方应用程序,作为 Helm 消费者,希望每个新应用程序版本都发布一个 Helm Chart。 这里的一个主要区别在于发布频率。 很可能像 MySQL 之类的第三方 Helm Chart 一天不会改变几次。 在这种情况下,您也不想意外地将旧版本的图表与新版本的软件一起使用 - 使用不是自己编写的软件和图表更容易犯这个错误。

对于第一方应用程序,您可能有部署一类应用程序的标准方法。 例如,在 Icelolly,我们以几乎相同的方式编写和部署我们的 Go 服务。 为此,我们现在实际上能够为部署在 Kubernetes 中的所有 Go 服务使用单个图表(我们现在使用helm package解决方法)。 如果我们部署自己的应用程序所采用的方法发生变化,我们将更新图表。 我们使用 SemVer 对我们的图表进行版本控制,因此未更新的应用程序在我们想要更新它们之前不会受到影响。

就在这张纸条上; 我们的go-service图表上次更新是大约一个月前。 在那段时间里,我们可能已经进行了数十到数百次部署——所有这些图表都没有改变。

在一种情况下,您只想要简单。 在另一种情况下,您需要控制和易于管理。

在这种情况下,您将松散应用基础架构清单和应用版本的耦合。 因为,更改图像标签不会触发新的 helm 升级(如果 Flux 人员以其他方式执行此操作,请纠正我)。 在这种情况下,您将使用 Helm 作为配置模板。 在这种情况下,您根本不需要 --app-version。

Flux 实际上会更改它用于升级图表的值,然后使用新的图像值运行升级。 您关于失去基础设施清单和应用程序版本耦合的观点仍然成立。 我要争论的一点是,在某些用例中确实需要这种情况。 你是对的,在这个用例中,我不需要--app-version ,它不会被使用,因为它现在不存在。 如果确实如此,也许 Flux 可以使用它。 在那种情况下,它实际上会有所帮助。

helm list是一个有用的命令。 能够查看部署了哪些应用程序版本确实仍然很有用。 对于我们目前使用helm package方法通过 Helm 安装的应用程序,我们只设置应用程序版本(通过--app-version上的helm package ),以便helm list的输出是有用。 这就是为什么如果我们可以将它设置为helm install|upgrade对我们来说会更简单。 我们不必为了更改版本而获取图表并重新打包它。

事实上, helm list和处理回滚可能是我们在第一方软件中使用 Helm 的唯一原因。

您在此处对 .deb 和 .msi 软件包的描述缺少一个关键组件 - 正在安装的实际内容。

“安装”是在目标平台上设置必要设施(文件夹、配置、二进制文件、数据库获取、数据刷新/迁移)的过程。

deb 处理所有这些。 Helm 包也是如此。 你的意思是 Helm 包没有“实际安装”?

如果您查看 .deb 文件的内容,您会发现内置软件 - 将要安装的软件。

错误的。 有时您会找到软件本身。 有时你会发现一些软件。 有时您只会找到一组脚本来获取此类软件。 所以,这里的关键点 -这并不重要,因为 Linux 和 K8s 是托管给定应用程序的平台,接受一种通用应用程序格式。 和图像名称,配置参数 - 是包的组成部分。

不过,Brew 目前实际上更类似于 Helm,因为它只是关于如何安装它以及应从何处下载源/包的说明。

确切地。 你是想说服我 Brew 不是包管理器吗?

这里要绝对清楚; Helm Chart _与特定的应用程序版本没有本质上的联系......
有多少应用程序允许您通过值覆盖正在使用的图像? (很多)

你是绝对正确的。 Helm 只不过是一个用于 k8s 模板的方便的模板引擎。 我对这种软件的存在没有任何问题:它有点帮助,不会改变现代交付实践。

问题是,Helm 不仅仅是模板引擎。 它是一个包装管理器,具有所有优点和缺点。 在包管理器存在的生态系统中,让其他包管理器管理某些东西是一种不好的做法。 更糟糕的是 - 在没有包管理器的情况下工作。

我看到了将应用程序版本作为这些包的包参数的原因。 我明白了你们和你们所有人不用打包的原因。 问题是,它已经过时、复杂且难以管理。 有趣的是,成本很小,但获得它却很棒。

我要争论的一点是,在某些用例中确实需要这种情况。

是的,这就是中心点:它适合任何产品吗?

您的论点是 Helm Chart 很少更改,所以我们为什么要在每个版本中将其打包在一起。 我同意你的看法,感觉是多余的。 但无论如何,我们仍然打包了一些旧的源文件、旧的 side-cars(如果 Helm 由多个应用程序组成)、旧的配置、旧的 Dockerfile。

所以问题是,如果我们将整个 Chart 打包为工件,在每次构建时,收益是多少? 对于 Dockerfile,这是显而易见的(但可以肯定的是,当容器化出现在市场上时,它并不明显)。 对于源文件也是如此。

在过去,我们拥有最清晰的传输机制:仅通过 FTP 上传更改的文件。 现在我们有这么多东西。 我们需要决定什么是好的,为什么好,谁应该使用它。 我不确定我是否会对 Helm 同时处理这两种方法感到满意 - 太复杂了。

部署第三方应用程序。

如果我可以单独使用 Helm chart 安装任何 PSQL/MySQL 版本,我会非常高兴。 维护遗留项目、为新手引入基础设施会容易得多。 更容易收到有关图表更新的通知。 为什么每个版本的二进制文件都有这么多 tar.gz 文件,但 Helm 包不能有相同的 tar.gz 文件集?

@iorlas我刚刚通读了这篇文章和被拒绝的 PR,你提出了一些非常好的观点。 你让我相信我需要开始打包我的舵图作为我的构建/发布的另一个工件。

但我想提一下,我什至不知道 helm 有一个 package 命令,而且我猜我并不孤单。 这可能是因为从源目录安装图表非常容易,而且文档并没有真正推销这个概念,甚至没有详细解释它。

package 命令显然有文档记录,但在快速入门指南中只有几个非常笼统的包在快速入门中出现了很多,但主要是在谈论如何安装 Helm 和不同的操作系统包. 最佳实践中也没有提到包装,我认为应该包括在那里捕获什么是包装以及它为什么有用。 我还检查了结构略有不同的v3 文档,但似乎也不太建议用户打包他们的图表。

通常我想提交一个 PR 而不仅仅是听起来像我在抱怨什么,但我不确定 3.0 文档更改发生了什么。

@jonstelly文档中肯定存在差距。 甚至我一开始也认为 --app-version 很好用,但后来虽然不能因为没有原因而遗漏它。

文档肯定需要一些澄清和常见问题介绍。 然后,Helm 开发周期介绍。 但我相信团队在第 3 个版本上很忙。 而且我现在也太忙了:(

“安装”是在目标平台上设置必要设施(文件夹、配置、二进制文件、数据库获取、数据刷新/迁移)的过程。

deb 处理所有这些。 Helm 包也是如此。 你的意思是 Helm 包没有“实际安装”?

我并不是说 Helm Chart 本身没有安装——我只想说,Helm Chart 不包含您正在部署的实际应用程序。 Docker 镜像未打包到 Helm Chart 中。 它由 Kubernetes 从一些外部来源拉取。

错误的。 有时您会找到软件本身。 有时你会发现一些软件。 有时您只会找到一组脚本来获取此类软件。 所以,这里的关键点 - 这并不重要,因为 Linux 和 K8s 是托管给定应用程序的平台,接受一种通用应用程序格式。 和图像名称,配置参数 - 是包的组成部分。

据我所知,实际上你在这里是不正确的。 .deb文件是一个 AR 档案。 您可以提取它并查看内容,最终它是一些元数据和一些文件。 .deb文件理论上可以包含补丁,但通常不包含。 如果.deb文件包含用于获取软件的脚本,则意味着.deb文件正在安装该脚本,而不是软件本身。 这就像安装安装程序。

如果您有一个打包在.deb中的 Linux 软件示例,其中.deb会下载要安装的软件,作为安装.deb文件的过程的一部分,那么我真的很想看到它 - 因为它是我使用 Linux 多年以来从未遇到过的东西。

确切地。 你是想说服我 Brew 不是包管理器吗?

不。我要说的是,像 Helm 一样,提供的用于通过 Brew 安装软件的脚本就是这样 - 脚本。 应用程序是单独构建、打包和分发的,并由这些脚本拉入。 这并没有让 Brew 成为一个包管理器,就像我一直在说的,并没有让 Helm 成为一个 Kubernetes 包管理器。 不过,这不是这个问题的重点,我们不是在争论 Helm 是否是包管理器,我们正在尝试决定是否应该将--app-version标志添加到helm install|upgrade以促进常见用例。

我看到了将应用程序版本作为这些包的包参数的原因。 我明白了你们和你们所有人不用打包的原因。 问题是,它已经过时、复杂且难以管理。 有趣的是,成本很小,但获得它却很棒。

抱歉,我不清楚你的意思。 什么是过时的/复杂的/难以管理的?

所以问题是,如果我们将整个 Chart 打包为工件,在每次构建时,收益是多少? 对于 Dockerfile,这是显而易见的(但可以肯定的是,当容器化出现在市场上时,它并不明显)。 对于源文件也是如此。

再次,区别基本上是你提到的所有这些事情都有内在的联系。 您需要所有源代码来运行应用程序 - 而不仅仅是更改的内容。 你没有打包 Dockerfile,所以不确定那点是什么 - 但是你经常会使用相同的 Dockerfile 而不更改它来构建新版本的图像(我的意思是,如果你必须手动更改某些内容,为什么还要自动化?时间,对吗?)。 有了所有这些东西,您就可以创建封装您需要的一切的东西,以便可以单独部署。 所以你可以做一些事情,比如启动一个新节点,并像部署到现有节点一样部署到它,等等。

有很多好处,我相信你已经知道了,通过 FTP 使用旧的上传。

不管怎样,这都是靠过去了。 我认为最终正如我已经提到的那样,在我看来,这一切都归结为; Helm 维护者是想要启用这个其他用例,还是让人们更难以这种方式使用它? 最后,无论哪种方式都_真的_差别不大。 对我来说,如果我不必打包我们的内部图表就好了,它很少改变,在每个构建中只是为了设置一个应用程序版本,这再次仅用于在列表中显示当前版本。 对于第一方应用程序,老实说,我怀疑 Helm 是否是正确的方法。

Docker 镜像未打包到 Helm Chart 中

其实,我希望是这样。 但现在不是。 我的愿景是,K8s 将/应该是一个平台,它将合并 Helm(因此将没有 Helm)作为 API 来安装包:您需要将您的东西打包到存档中并安装它。 回到 deb 文件的简单性,但具有适当的隔离和 k8s 资源作为一等公民。

.deb 文件是 AR 存档
您可以提取它并查看内容
最终它是一些元数据
和一些文件

就像……一个 Helm 包!

如果您有...一个.deb .deb 所在的位置并下载要安装的软件,作为安装 .deb 文件过程的一部分...
这就像安装安装程序。 ...

是的,它就像一个安装程序,里面有安装程序。 有趣,对吧? 如果可能的话,我会足以设置应用程序实例。 但是我们有不同的软件,不同的真相来源,有时拥有多个来源甚至很方便。

  • Brew 将 YAML 作为一个包,但从远程存储中获取二进制文件
  • Emerge(gentoo) 有 ebuild 作为定义,它甚至下载 git clones

Debian 试图把所有东西都打包进去。 如果可能的话,这是正确的做法。 但是为了证明我的观点,元数据包就可以了。 你有没有听说过这件事? 它是一个包,它安装了一些其他包。 不是包裹吗?

但是请不要错过要点:没关系! 即使是只有内部引用的空包,也是一个包。 也许你会接受另一个术语,安装人员?

我的意思是,像 Helm 一样,通过 Brew 提供的用于安装软件的脚本就是这样 - 脚本
应用程序分别构建、打包和分发,并由这些脚本拉入

我们都有相同的管道 - 构建 docker 镜像。

我们正在尝试决定是否应将 --app-version 标志添加到 helm install|upgrade 以促进常见用例。

那是一把钥匙。 但是我们如何决定呢? 我们应该问两个问题:

  • 是否可以? 是的
  • 这样做是对的吗? 是的? 不?

如果有人在做某事,是否意味着这是一件好事? 为了取得进步,我们需要质疑一切。

抱歉,我不清楚你的意思。 什么是过时的/复杂的/难以管理的?

让项目到 Brew 上,因为 Brew 非常接近 Helm 并且已经被广泛、成功地使用。 您可以投影到 Gentroo Ebuilds 或 deb,图片不会改变。

  • 过时了。 您最后一次必须手动安装 MySQL/PSQL 是什么时候? 为什么我们已经摆脱了它? 这些原因,萌。
  • 复杂的。 这是“为什么”之一:您需要独立设置基础设施,您需要知道哪个最适合哪个软件版本。 有时您需要自定义基础架构以运行特定软件版本。 何必呢? 你为什么不代表整个问题?
  • 更难管理。 当您只能拥有一个工件时,您将需要同时管理基础架构和应用程序版本。 为什么让你的生活更艰难?

抱歉,现在描述所有用例有点懒惰,比如干净的回滚,优雅的升级,无论如何这些是主要的好处。

再次,区别基本上是你提到的所有这些事情都有内在的联系。

不总是。 例如,docker 镜像可以有 SSR BE 和对 CDN 的引用。

Dockerfile,所以不确定那点是什么 - 但你经常会使用同一个 Dockerfile 而不改变它来构建新版本的图像(我的意思是,如果你每次都必须手动更改某些内容,为什么还要使用自动化,对吗?)。

这才是重点。 即使 Dockerfile 未更改,您也会构建新映像。 如果您的源代码未更改,但 Dockerfile 更改,则您构建新映像。 所以,简而言之,Dockerfile 也是一个包。 Helm 也是如此。 你不这么认为吗?

有了所有这些东西,您就可以创建封装您需要的一切的东西,以便可以单独部署。 所以你可以做一些事情,比如启动一个新节点,并像部署到现有节点一样部署到它,等等。

但事实证明 docker image 不足以运行应用程序。 我们需要一个配置实例,我们需要服务定义。 为什么不全部打包?

最后,这两种方式都没有太大的区别。

我相信,是的。 也许这不是代码库中的重要内容,但它会阻碍容器化的发展。

Docker 镜像未打包到 Helm Chart 中

图像本身没有打包,但参考(读作:pin)是。 当然,我们可能会迂腐,并关注不同大小(从 MB 到 GB)的文字图像是否包含在helm package的工件中(剧透:它不是),但本质“应用程序代码的给定版本包含在 helm 包中”这句话从根本上来说仍然是正确的。 你是否想陷入如何是无关紧要的。

让我们回到实例的土地,让我们说,你有你的内部版本作为应用1.9.9的版本图表上运行1.2.5 。 为了避免混淆,应用程序容器的 Docker 镜像是fakeshaA

您的团队决定在您的应用程序的2.0.0版本中将有一个文件的本地文件系统版本,您过去必须通过 HTTP 引用该文件。 这样做的原因并不重要,但对您造成的后果非常严重。 现在您需要一个pv和一个pvc用于您的部署,以便这些现在本地的文件不会在升级之间丢失。 看到需要,您继续更新您的 Helm 图表以使用pvpvc这样转移到2.0.0就不会造成超级破坏。

在更改图表之前,您有Artifact A将应用程序版本1.9.9到基础架构版本1.2.5 。 现在您更改图表... _your Helm Chart 现在是 v. 1.3.0 _,您将生成一个将1.9.9到基础架构版本1.3.0的工件。 我们称之为Artifact B

2.0.0的代码部署与 Docker 映像 sha fakeShaB ,您将创建另一个将2.0.0到基础版本1.3.0工件。 这是Artifact C

现在假设事实证明 2.0.0 版本存在一个您不完全理解的问题,您必须回滚。 您使用Artifact B回滚 ... 但这并不能解决问题,因此您再次回滚到Artifact A并解决了问题。

您遇到的唯一问题是您的工件引用的 Docker Registry 是否仍然具有在这些工件中引用的图像。

无论如何,您仍然可以在应用程序版本和基础设施版本之间建立联系。 这就是 Helm 的目的。 否则争论是愚蠢的。

@iorlas :

让我们把.deb比较放在一边。 我认为这只是我们偏离了方向。

不总是。 例如,docker 镜像可以有 SSR BE 和对 CDN 的引用。

这是非常正确的。 稍后再谈。

这才是重点。 即使 Dockerfile 未更改,您也会构建新映像。 如果您的源代码未更改,但 Dockerfile 更改,则您构建新映像。 所以,简而言之,Dockerfile 也是一个包。 Helm 也是如此。 你不这么认为吗?

确实如此,但那是因为构建过程结束时的产品(即 Docker 映像)取决于 _both_ Dockerfile 以及您放入其中的内容。 没有这两个组件,图像就无法存在。

另一方面,Helm Chart 甚至可以在构建应用程序之前就已经存在——实际上是在编写一行代码之前。 您可以构建一个无法安装的假想的图 - 但尽管如此,Helm Chart 可以完全没有其他任何东西而存在。 就像我说的那样,这没有用,但我只是想说明我的观点,即它们根本没有联系。

我在这里的观点以及它与这个特定问题的关系只是 Helm Charts 并不总是与 Chart 部署的应用程序有内在联系。 我不认为这是一个大胆的主张,它发生了 - 这已经是事实。 我现在正在使用生产应用程序进行此操作,其他已对此问题发表评论的人也是如此。 正如我之前所说,这一切归结为; Helm 维护者是否想要启用这个用例,或者不 - 没有别的了。

但事实证明 docker image 不足以运行应用程序。 我们需要一个配置实例,我们需要服务定义。 为什么不全部打包?

其实,我希望是这样。 但现在不是。

如果是这种情况,并且 Helm Chart 实际上确实打包了它部署的所有内容(您之前提到了 CDN,但您当时没有将其部署到 Kubernetes,因此它甚至不会进入您的 Chart),那么我认为这场谈话不会发生。 您的 Helm Chart _将_内在地链接到正在部署的应用程序版本 - 就像构建 Docker 映像一样。 要在这种情况下构建 Helm Chart,您需要在应用程序更改时重新构建它,此时毫无疑问。 你不能像我今天使用的那样使用 Helm - 这样会更清晰。

然而事实并非如此。 这不是 Helm 的工作方式,而且我不知道它最终会不会真的如此。 但永远不要说永远,对吧?


@jrkarnes

图像本身没有打包,但参考(读作:pin)是。

当然,但一个常见的用例是使用值来覆盖这个值。 我已经将它用于第三方和第一方图表。 如果它不是人们使用的东西,它就不是一种选择。

当然,我们可能会迂腐,并了解不同大小(从 MB 到 GB)的文字图像是否包含在 helm 包的工件中(剧透:它不是),

我不认为我们在任何事情上迂腐——就像你已经指出的那样,说 Docker 镜像被打包在“构建的”Helm Chart 中实际上是不正确的。

“应用程序代码的给定版本包含在 helm 包中”从根本上来说仍然是正确的。

但并非如此,因为我的第一点会反对。 您可以更改正在部署的内容。 见鬼,如果需要,您可以更改大多数图表以运行hello-world图像。 那没用,但它很好地证明了我的观点 - Helm Chart 未链接到您的应用程序。 _期望_您将使用它与正确的图像,并且可能默认情况下它会这样做,但它肯定不会_必须_ - 并且_绝对_是应用程序的代码包含在 Helm Chart 中,否则打包。

回到例子的领域,[...] 问题就解决了。

如果不以目前显然是预期的方式使用 Helm,您认为这是不可能的。 但实际上,您只能拥有 2 个版本的图表(即您的两个基础架构版本)和 3 个版本的应用程序。 如果你想回滚,那就去做吧,你可以很容易地选择你想要部署的图表和图像。 使用您的 Chart 运行 Helm,相应地为图像设置您的值,然后就大功告成了。

无论如何,您仍然可以在应用程序版本和基础架构版本之间建立联系。 这就是 Helm 的目的。 否则争论是愚蠢的。

我认为争论(最好是讨论)事情如何改变通常会导致事情的改善。 我认为 Helm 的“目的”不是链接 Chart 和应用程序版本。 我认为它的目的是使将应用程序部署到 Kubernetes 集群更容易、更安全,同时保持 Kubernetes 清单干燥和可重用。 在那里你不需要严格链接图表和应用程序版本(就像现在的现实一样,你不需要它们)。

再说一次,正如我对@iorlas 所说的,问题是 Helm 应该适应吗? 不启用此用例的原因是什么? 如果原因只是“因为目前还没有”,那么如果你问我,那是一个非常糟糕的理由。 到目前为止,这些讨论似乎都没有回答这个问题。

...构建过程结束时的产品(即 Docker 映像)取决于 Dockerfile 和您放入其中的内容。 ...没有这两个组件,图像就无法存在。

所以... Helm 包需要 Chart 和应用程序版本(= Docker 镜像),并且没有它就不能存在。

Helm Chart 甚至可以在构建应用程序之前就存在——实际上是在编写一行代码之前。 ... Helm Chart 可以完全没有其他任何东西。 就像我说的,这没用

有趣的是,在一个项目中,我们曾经使用 stub docker 图像来创建原型架构。 我们确实使用了 Charts,而无需编写一行代码。 此外,拥有仅由子图表组成的图表总是可行的。

所以,我的假设是:Helm 包在没有 Docker 镜像的情况下几乎没用。 没有源代码的 Docker 镜像几乎没用。 区别在于抽象级别。 两者都是类似包的对象

但我只是想说明我的观点,即它们根本没有联系。

是的,是的! 这真是太好了,我们已经准备好讨论所有细节。 没有你,没有预测和断言,我们不会让未来的麦汁生活😃

我不认为这是一个大胆的主张,它发生了 - 这已经是事实。 ......所以正如我之前所说,这一切归结为; Helm 维护者是否想要启用这个用例,或者不 - 没有别的了。

事实。 为了做出和接受这样的改变,应该评估:这样做是否

让我给你讲一个故事。 Martini 是一个伟大的、广泛使用的 Web 框架。 原因不是缺乏投入的时间,而是一些有执照的恶作剧。 因此,让未来更美好的唯一方法是弃用整个框架,激怒一些人,让一些项目成为孤儿,迫使一些人重新评估他们所做的事情。

所以,我并不反对这种方法。 我知道它是如何生存的(用helm run查看我的提案)。 但是,虽然我们有机会进行干预,并可能在为时不晚的情况下修复整个行业,但我会评估每种用法,讨论任何缺点和问题。

要在这种情况下构建 Helm Chart,您需要在应用程序更改时重建它

对。 即使是现在,这也可能是一个案例。 我们有一个管道,而不是push我们正在做 docker 镜像的save / load 。 它运作良好。 我现在不喜欢它,但从根本上说它是更清洁的方式。 问题是,K8s 仍然需要远程 docker 注册表作为总线来传输“启动器”——docker 镜像。

让我们缩小我们的焦点,伙计们

您的 Helm Chart 将与正在部署的应用程序版本内在链接 - 就像构建 Docker 映像一样。

这是一个关键的区别。 @seeruk 搞定了。 我们可以专注于它。 让我将其解释为事实:

  1. Docker Image 没有绑定 Helm 包。 仅供参考。
  2. 这提供了独立释放这些路径的机会。

关键问题:

  1. 独立方法的风险是什么? (即,如果某些 DevOps 会使用它,我们会反对它的论据是什么)
  2. 包装方式如何解决?
  3. 费用是多少?
  4. 在这个特定问题中,我们如何看待容器化的未来?

@seeruk

再说一次,正如我对@iorlas 所说的,问题是 Helm 应该适应吗? 不启用此用例的原因是什么? 如果原因只是“因为目前还没有”,那么如果你问我,那是一个非常糟糕的理由。 到目前为止,这些讨论似乎都没有回答这个问题。

你做了很多很好的澄清和观点。 我个人认为 Helm 应该适应。 CI/CD 是软件构建方式的未来,老实说,像--atomic helm 作为可靠的部署工具已经变得更加灵活。 不过,这个问题已经很老了,所以我认为合并 PR 不是过程中的“下一步”。

创建一个插件,比如helm-ci-cd对于这个特定的--app-version功能是否可行( @jrkarnes可能会作为公关贡献者与这个人交谈)? 我认为社区关于让 Tiller 退出的需求只有在该插件起飞后才真正得到承认。 Helm 还存在其他各种很容易绕过的问题,这可能是helm-ci-cd其他很好的候选者,看起来我们 CI/CD ppl 已经通过包装统一了install/ upgrade对偶性。

即使--app-version开关对于尝试安装 k8s 应用程序而无需查看模板文件的最终用户来说不是直接的增值(顺便说一句,实际上从未真正解决过我因为需要添加网络策略以符合我的工作 k8s 基础设施)最终用户仍然获得了更多价值,因为构建该图表的人可以更轻松地完成它,因为 helm ci/cd 功能使构建稳定和可靠的软件更容易。

我们只是使用 groovy 读取 Chart.yaml,然后设置应用程序版本并在部署期间覆盖文件。 然后进行掌舵升级。 如果它是 helm 的一部分就好了,但我不会指望它。

通过谷歌找到了这个。 实际上是同一条船。

如果verison:是 Chart 版本,则意味着当 Chart 的 YAML 更改时,此版本也会更改。 由于图表是具有可配置值的模板,因此可以安全地假设您可以使用图表 1.3 来部署多个版本的应用程序,1.2、1.3、1.6、1.8 等,而无需每次修改图表的 YAML 文件。

现在appVersion:硬编码在 Chart.yaml 中——强制您编辑图表文件以更新(和反映)已部署应用程序的版本。

肯定需要一个--app-version CLI 选项,我们可以在图表模板中使用它来引用 _application_ 的版本,以部署具有相同version: 1.3.0图表的不同版本。

@seeruk

我认为 Helm 的“目的”不是链接 Chart 和应用程序版本。 我认为它的目的是使将应用程序部署到 Kubernetes 集群更容易、更安全,同时保持 Kubernetes 清单干燥和可重用。

这是我们的争论点,我认为我们中的任何一方都无法说服对方。 有时在专业环境中,当涉及到意见问题时,存在不可调和的分歧是可以的。 我当然不同意 Stallman 所说的一切,如果我们就他和我不同意的所有事情深入研究,我们将在达成共识之前死去。

我在讨论中进一步说了,我认为值得重复一遍:

[...] 我猜测 helm 只会真正部署包。 这似乎是你能说的唯一语义正确的东西; 然而,关于这些包如何分发的争论似乎是实践中这场争论的根本原因。 具体来说,“升级或更改应用程序版本是否构成新包?”

没有配置的第一方掌舵图表(我喜欢使用 MySQL,所以我将继续使用它)应该将资源安装到集群中,因为图表创建者描述了它并打算使用它查看 mysql 的实际图表,有两个可配置的属性涉及实际的 mysql 引擎:

  • image (默认mysql )
  • imageTag (默认5.7.14 )

然后,在他们的Chart.yaml文件中:

apiVersion: v1
name: mysql
version: 1.4.0
appVersion: 5.7.27

请注意, appVersion和默认的imageTag不匹配。 如果我运行helm list我将得到一个报告,指出“应用程序版本”(读取;引擎版本)是一种状态 _ 不反映安装到集群中的实际应用程序版本_。

在那里你不需要严格链接图表和应用程序版本(就像现在的现实一样,你不需要它们)。

这是对的; 在我看来,这是一个设计缺陷。

再说一次,正如我对@iorlas 所说的,问题是 Helm 应该适应吗?

是的。 稍后我将提出一些建议。


@IRobL

创建一个插件,比如 helm-ci-cd 对于这个特定的 --app-version 功能是否可行( @jrkarnes可能会作为 PR 贡献者与这个人交谈)?

你回答你自己的问题:

即使 --app-version 开关对于尝试安装 k8s 应用程序而无需查看模板文件的最终用户来说不是直接的增值,最终用户仍然会获得更多价值,因为由于 helm ci/cd 功能可以更轻松地构建稳定可靠的软件,因此构建该图表变得更容易。

如果我们必须将其作为插件来使功能正确,那么我会提倡这种方法; 然而,我认为这是在解决错误的问题。 正如我之前对@seeruk所说的那样,我认为将appVersion设为不可变Chart.yaml文件中的固有属性是一个设计缺陷。 appVersion是通过图表安装到集群中的image一个属性,它以某种方式从用其tag引用的图像派生而来。

在考虑helm-ci插件时,您希望有哪些其他功能或插件? 我不认为简单地从不可变的appVersion Chart.yaml属性中切换appVersion就足以保证成为插件的增值。


@IRobL@seeruk在一起:

我认为我们的不同意见来自于我们认为更常见的掌舵最终用户是谁。 如果最终用户应该是不会进行大量配置或深入研究模板的人,那么helm ls可能不是特别有用,而且这一点没有实际意义。

但是……如果您使用 helm 作为管理工具和助手来管理集群,或者如果您在更多 CI/CD 上下文中使用 Helm,那么--appVersion开关最终会更多更有用,因此是一个关注点(和配置),

在一个完美的世界中,我认为appVersion应该是一个派生属性并且来自 docker 图像元数据; 这对于掌舵人来说是不可行的,因此,缺乏争用。

对于我所说的

是的。 稍后我将提出一些建议...
...在考虑helm-ci插件时,您希望有哪些其他功能或插件?

我有一个个人列表,它可能是一个很好的起点:

  • CICD模式下运行helm不会_仅_比较以前发布的包的状态与当前正在应用的包的状态。 . 相反,当upgrade运行时,发布的每个部署都将完全应用模板化的每个清单。
  • helm-cicd应该包装基本的 kubernetes 命令。 我无法计算我尝试运行helm describehelm logs
  • helm-cicd应该允许我查看由不同用户运行时命令的结果。 如果我们使用 RBAC,我想看看当未经授权的用户尝试做某事时会发生什么。
  • helm-cicd应该能够将命名空间分解为一组清单以供稍后编辑。
  • helm-cicd应该能够将发布_移植_到命名空间中。

这些都是重要的......但是讨论一个成熟的helm-ci插件不在这个 PR/问题的范围内(当前)。

我确实阅读了你们输入的所有内容,我很欣赏这些演讲。 我期待着您的回复。

我现在很忙,但想纠正你几点。 @jrkarnes

我认为让 appVersion 成为不可变 Chart.yaml 文件中的固有属性是一个设计缺陷

它不是。 当某种东西以这种方式而不是另一种方式制造时,总会有一个原因,即使是野生的。 在这种情况下,这是我所坚持的意识形态:一个包 = 一个构建,图表 = 构建模板,包 = 应用程序 + 基础设施。

Helm 是围绕这一理念设计的,将 K8s 视为操作系统,并将其打包为应用程序的安装程序/更新程序。 它有一些问题,有时感觉太多了,但它肯定是未来。

_为什么我认为它是这样设计的? 相同的helm list设置为显示当前安装的软件包版本。_

好的,我们有很多 Charts(像 mysql 这样的公共和本地,就像你可能拥有的那样)并不是每次新版本出现时都会创建一个包。 我很欣赏这种需求,因为迁移到高级解决方案需要时间。 此外,有人需要构建包,而且很难说服 mysql 维护者为每个构建创建 Helm 包。

使用 MySQL 图表还有一个额外的问题。 你说得对,最好在helm list看到 MySQL 版本安装,但它只是版本的一部分,因为还有一个 Image 标签,它可能是这里版本的一部分。

再说一次,正如我对@iorlas 所说的,问题是 Helm 应该适应吗?
是的。 稍后我将提出一些建议。

同样,有人提议添加helm run ,这正是你们正在寻找的。 Is 旨在立即使用 Chart 作为包,允许提供应用程序版本等。

在一个完美的世界中,我认为 appVersion 应该是一个派生属性并且来自 docker 图像元数据; 这对于掌舵人来说是不可行的,因此,缺乏争用。

您将 Docker 映像视为最终产品,作为最后一个包,这是最后的真相来源。 它不是。 当您只有一个 Docker 镜像时,您可能会误以为它是您的软件。 当您在代码中编写模块时,您会误以为该模块是您的软件。

问题是,它不是。 它只是一部分,神器。 从小到大的产品,您都会将许多工件捆绑在一起。 有时您会在构建过程中在 docker 文件中传递版本,有时您会有一个 ConfigMap,它将多个工件联系在一起。 而且您不会拥有一个包含所有内容的 docker 文件。

我有一份个人清单,这可能是一个很好的起点

我相信你有很多建议,但感觉更像是一个Helm fork ,而不是一些狂野的插件。 我会说它与CD的CI无关。 我认为不要构建这样的分支/插件,而是讨论并提出适当的解决方案。 没有人需要 3 个 Helm 分叉,考虑到当前社区目前还没有那么大。

请注意!

好吧,我们有很多想法。 我相信最好的情况是:

  • 能够更改应用程序版本,无需先创建包
  • 能够在helm ls查看正确的应用程序版本
  • 允许任何 API(如 Helm 运算符)指定/升级没有中间状态的应用程序版本

我们提供了两种方法:

  1. helm install用于安装软件包。 它也支持安装图表,但它是有限的。 让我们简化helm install并让它服务于它的目的 - 安装包。 其次,让我们添加helm run ,其目的是提供简化的流程:结合helm packagehelm run ,提供两个命令参数,但过滤掉在这种情况下没有意义的参数.
  2. app-version添加到helm install cmd 中。 它会膨胀这个 API 并隐藏使用包的想法,它将隐藏(就像现在一样)使用包作为安装程序的意识形态,这至少对于某些(如果不是大多数)项目是完全有意义的。

我们是否同意这两种方法将解决我们目前遇到的所有困难?

插件是核心开发人员不想支持或没有时间支持的缺失功能的解决方法,所以我不在乎它是否是插件。

Helm 是围绕这一理念设计的,将 K8s 视为操作系统,并将其打包为应用程序的安装程序/更新程序。

哦。 我知道了。 Helm chart [package] 是 Kubernetes 的“rpm”[per-say]。 完全不是我得到的印象:helm 使用 Charts 来部署应用程序。 图表/包是“为 k8s 格式化”的应用程序。

我没问题。 这是有道理的 - 我们现在需要在构建新容器时更新我们的构建服务器以升级 appVersion:

  • 构建容器 - 标记“v1.2”
  • 更新 Chart.yaml - appVersion: "v1.2" --- 我看到已经有helm package --app-version命令了。
  • 包图表: helm package --app-version v1.2 => package[chart]-v1.2.tgz(即一个“package[chart]-v1.2.rpm”)
  • 使用部署服务器部署包, helm install package[chart]-v1.2 (eg apt install [email protected])

现在,我对这些的理解有误吗? 如果 package-v1.2 不是 v1.2 appVersion,为什么不呢? 这不就是本意吗? 例如 rpm 是应用程序的版本,而不是包(图表)。

编辑:

如果 package-v1.2 不是 v1.2 appVersion,为什么不呢? 这不就是本意吗?

现在我明白为什么人们一致评论 Chart.version 和 Chart.appVersion。 参数在这里可以双向使用……具有稳定“图表”构建的应用程序,您希望 package-v1.2 更改其版本号。 但是您也可以争辩说 package-v1.2 将是 Chart 版本号 - 当 yaml 文件更改时。

您如何管理稳定的 Chart 版本 (1.2),区别于不断增加的应用程序版本 (1.6)? package-[version]会是 1.2 吗? 还是1.6? 假设您部署了 Chart 1.2 版,但 appVersion 在包装上发生了变化: helm package --app-version 1.6

➜  chart git:(master) ✗ helm package --app-version 1.5 nginx
Successfully packaged chart and saved it to: /Users/Documents/source/docker/nginx/chart/nginx-0.1.0.tgz

:(

……好纠结。

Helm chart [package] 是 Kubernetes 的“rpm” [per-say]

确切地! 但有时感觉太严格或太麻烦,这就是需要捷径的地方。

现在,我对这些的理解有误吗? 如果 package-v1.2 不是 v1.2 appVersion,为什么不呢? 这不就是本意吗? 例如 rpm 是应用程序的版本,而不是包(图表)。

这是另一个讨论的问题,但目前包将以图表版本命名,而不是应用程序版本。 不知道是什么原因,我觉得应该是相反的。 我认为,这是历史问题,但在我看来,和你的一样,它应该是package-{app-version}.tgz

根据我之前的消息,版本有 4 个组件:

  • 图表
  • 应用程序
  • 包裹
  • 发布

独立地对所有这些东西进行版本控制是一件令人头疼的事,但这就是它现在的工作方式。 有一个例外:包在图表版本之后进行版本控制。

如果我们选择打包应用程序的意识形态,应用程序版本将完全有意义,因为相同的过程生成应用程序、图像和包。 因此,当我们进入交付步骤时,很明显如何调用文件,安装哪个文件。 现在我们必须在管道中硬编码包名称 >_<

@iorlas

您将 Docker 映像视为最终产品,作为最后一个包,这是最后的真相来源。 它不是。 当您只有一个 Docker 镜像时,您可能会误以为它是您的软件。 当您在代码中编写模块时,您会误以为该模块是您的软件。

我花了几个星期来考虑这个声明,我 100% 同意你的意见。 此外,我现在明白了我们意见分歧的来源……

我遵循一种开发和部署理念,即您应该用小组件构建一个系统,这些组件可以很好地完成一系列事情(想想 UNIX); 然而,现代系统可能会将“应用程序”视为这些小工具的组合。 当应用程序不仅依赖于 docker 工件,还依赖于其他子组件(也可能是 docker 工件)时,您应该如何标记应用程序的“版本”? 当您开始抛开这种类型的耦合时,这并不是一个简单的答案。

回答这个问题远远超出了这个问题/请求的范围。 为了回到问题的根源,我想区分installrun 。 从语义上来说, install应该只对包进行操作, run应该“运行”helm 生成模板并应用它们的过程_不维护状态_。

虽然很多时候我们应该使用helm template来查看预期图表将如何部署,但在观察它发生时有很多用处 vi-ca-vi run成为开发管道中的明星的双重目的(我们不一定要保留一个包,因为如果速度非常高,它就没有价值)。

使用 MySQL 图表还有一个额外的问题。 你说得对,最好在 helm 列表中看到 MySQL 版本安装,但它只是版本的一部分,因为还有一个 Image 标签,它可能是这里版本的一部分。

就像我说的,在一个完美的宇宙中,安装对象的版本会被内省。 然而,这确实给了我一个想法。

如果我们牢记我之前所说的关于如何部署图表的内容,如果我们能够使用helm describe上的标志展开所有子组件会怎样? 这并没有解决指定 app-version 的需要,但它确实使安装的内容更加清晰(这是想要用标志调整 app-version 背后的驱动力的一部分)。

我阅读了所有评论,但对此事没有完全限定的意见。

我来到这里是因为我的公司维护着一个私有的 Helm 存储库,我们 90% 的图表主要是一个部署,有一个容器规范。 在这些情况下,如果我们可以使用appVersion来列出图像的标签,我们就可以避免重复变量,我们将能够看到这个版本运行helm version

阅读此线程后,在我看来这将是一种方便,尽管如果它被合并,我会使用它的一个非常好的方法。

根据要求,我将在上一个帖子中包含我的最后回复,供其他人查看


唔。 当您开始将appVersion绑定到 Docker 标签(逻辑关联)时,这就是事情开始变得不一致的地方。 这就是我们遇到麻烦的地方,即我上面提到的开发场景。 由于version必须是 SemVer,我们根本不能将 Docker 标签用作 Chart version

appVersion在图表上不明显时,我们如何为开发人员创建视觉版本差异?

由于 k8s 与它的应用程序的工作方式:在开发世界中,有一些方法可以全面允许标签版本。

就 ~ 或 ^ 运算符而言,它无法像 SemVer 那样做事,因为版本纯粹是有序的,没有语义。

为什么不? 我们一直使用 php composer 。 我们可以使用 SemVer 或者我们可以使用在版本控制模式中被简单解析或忽略的字符串版本,即如果version不是 SemVer 编号,则不要将其包含在~^模式匹配。

由于您引用了我对 #7299 的评论,我会将“它不能”澄清为“它没有”(也许仍然没有)。

对于 .deb 和 .rpm 包,版本字符串以特定方式(通过连字符)分割,但它们没有语义含义,例如“这是 API 兼容的”,因此您不能生成像“给我最新的 API 兼容版本”或“给我一个 API 不变的最新版本”,就像 SemVer 一样。

我记得 Debian 和 RedHat 都使用包别名来实现那些通常基于版本号的用例(和 ABI 兼容性)。 这允许仅使用包名称和仅排序比较的合理一致的行为。

在一般主题上,我们将 Helm charts 用于我们的产品的方式是打包我们的各种服务。 然而,Docker 镜像只是一个工件,它们的命名是由服务版本驱动的,我们采用了 SemVer,因为它们提供了 API。

我们的 CI 管道将代码和相关脚本的 git 存储库转换为可安装的 Helm 图表,并且恰好引用了 Docker 镜像。 我们的用户对 Docker 镜像上的标签并不感兴趣。 然后我们用它们来自的 git SHA 标记,然后重新标记发布中使用的图像。 重新标记的主要好处是我们知道永远不要取消标记那些,而我们可以在短时间内取消标记 git-SHA 版本。

所以我对 Helm 为我们工作的方式感到非常满意,因为version包含我们软件的确切版本,而appVersion包含相同的内容但作为一个字符串,没有人会查看在我们的 Docker 仓库中。

我对https://github.com/helm/charts/ 中图表的版本化方式不太满意,因为图表是版本化的,而不是软件,导致偶尔出现次要(稳定)图表version更新破坏向后兼容性。 我认为当您将图表的version与其包含的事物的版本分开时,这是一个可能且难以避免的后果。

在我们内部的“外部使用的库和工件”页面中,我们对stable/prometheus-operator图表也有类似的问题。 它包含一堆不同的软件,所以问题是“我们使用的是哪个版本?” 尤其是“升级安全吗?” 比 Agones 更难回答,后者的版本与我们的做法相同。

@jrkarnes

如果我们牢记我早先所说的关于如何部署图表的内容,如果我们能够使用 helm 描述的标志展开所有子组件会怎样? 这并没有解决指定 app-version 的需要,但它确实使安装的内容更加清晰(这是想要用标志调整 app-version 背后的驱动力的一部分)。

我绝对很想看到那个。 例如,#6932 处有一个相关的功能请求。

刚刚回顾了讨论, appVersion与 Docker 镜像元数据相关的想法绝对不适合我们的用例,至少我们的一些图表(我们的用户主要处理的图表)确实如此不包含 Docker 镜像,主要是共享资源的主机(例如,JWT 公钥, values.yaml )加上一个requirements.yaml以拉入其他图表。

appVersion 与 Docker 镜像元数据相关的想法绝对不适合我们的用例,至少我们的一些图表

我不是说这是 _the_ 预期用途。 我只是说这是一个合乎逻辑的关联。 您仍在使用appVersion作为内部 yaml 的“逻辑容器”。

我仍然不知道将version锁定到 SemVer 有什么好处。 能否掌舵只是解析测试version (和appVersion )并从那里继续?

我想我的意思是我们根本没有使用appVersion ,它通常不存在于我们的 Chart.yaml 中,当它存在时,它与version

version锁定到 SemVer 的好处是您可以在其上使用各种 SemVer 运算符,并可靠地解析它以通过安装生成排序和匹配。

RPM 和 DEB 打包系统具有相同的东西,只是它们的版本控制系统使用不同的语法,但出于语义解析的原因仍然是受限制的语法。 它们也有不同的语义。

鉴于 helm/charts 存储库的运行方式,我觉得带有 DEB 或 RPM 样式版本的单个version字段比 SemVer 加上appVersion字符串更好。 然而,这是一艘完全不同的、已经航行的船。 我年轻时既是上游供应商又是 Debian 打包商,我很感激不必纠结于“哪些版本号需要在这里增加?” 在我们的“ version是唯一的真理”包中。

“有时是 SemVer”的问题在于,SemVer看起来很像解析器无法区分的东西,您可能会手工编写或在其他地方遇到,例如没有纪元的 Debian 软件包版本,结果令人困惑.

你好。 没有关于此功能的消息。

阅读完所有评论后,我可以看到这真的很有帮助。

事实上,在我们公司,因为我们有几个使用相同技术并以相同方式部署的应用程序,我们为不同的应用程序准备了一张图表以避免重复。
我们仅在基础结构发生变化时才打包新图表。
并且只有当我们升级或安装一个版本时,我们才会应用特定的值作为标签、环境变量......

我们认为打包的 helm chart 是代表 kubernetes 资源和一种应用程序预期结构的抽象层,只有在部署期间我们才会说“好的,我希望这种应用程序使用这些特定值部署在那个环境中”

由于 helm list 应该显示发布信息,我们应该能够看到在此版本中部署的应用程序的版本。

我在类似问题https://github.com/helm/helm/issues/7517 中留下了评论
我们可以在 values.yaml 中添加覆盖它的能力吗?
然后我们得到了免费的命令行选项--set

如果我们尝试将 helm 用于任何应用程序,这绝对是糟糕的。 没有人将语义版本控制用于生产应用程序。

我同意。 我们目前因将 Chart Museum 用于基于 _application_ 的不可变图表而被阻止。 Chart version != app version,让我们无法通过Chart Museum发布。

我通读了上面的一堆(不是全部)讨论,很抱歉,如果我重复了一些观点/观点。 我试图提出一个更深思熟虑的回应。

我喜欢在执行helm ls时看到 appVersion 并且从概念上讲从.Values.image.tag是一个不错的选择,但无法在部署时设置它是一个真正的障碍,这是我所拥有的恢复到。

我坚信(图表) version是图表的版本,而appVersion是 docker 标签。 在我们的 CI 过程中,docker 标签也是一个 git 标签。
我们还有多个微服务,并希望尽可能保持 DRY。 我们在本地图表存储库中有通用图表,因为大量的 java-springboot 应用程序是相同的。 大部分 tomcat 应用程序是相同的(但与 springboot 应用程序不同)。 冲洗并重复其他技术。 然后我们有环境值,因为部署通过各种环境
然后,这些微服务中的每一个都通过 CI/CD 使用通用图表
例如helm upgrade release-name private-repo/generic-chart --values <environment>.yaml --set image.tag=<docker tag from build step> --namespace <environment> --install我更喜欢使用.Chart.AppVersion而不是.Values.image.tag但我必须能够以对我们的组织有效的方式进行部署。

如果我做helm ls我有CHARTAPP VERSION所以整个图表版本必须匹配应用程序版本就在它的脸上。 继续沿着这条路线走只会疏远人们,并且在某些时候该项目将被分叉,因为这种心态过于严格,而不是许多人所追求的。 它也开始沿着“让我们删除image.*nameOverridefullnameOverride . image.* 可以在 deployment.yaml 等中进行硬编码”的路线走下去。 出于非常相似的原因。

最后一点是,许多公共图表与他们使用的 docker 容器版本不完全匹配。 看看最著名的 docker 容器,例如 alpine 或 nginx,其中主要和次要版本是滚动标签,只有补丁版本不滚动。 对每个补丁版本进行 1:1 映射会带来相当大的开销,但几乎没有任何好处。
由于多种原因,生产环境无法升级到最新版本的情况并不少见。 甚至不要在大多数地方谈论生产中的滚动版本。

以上所有的结果都引出了一个问题“为什么 helm 可以使用图表存储库?”。
无法在安装/升级时覆盖appVersion意味着您已经需要下载和解压缩图表,每次安装/升级编辑appVersion ,或者您也可以将所需的 docker 容器打包到图表。
例外情况是完全标准的安装正在发生,并且围绕自动生成密码等已经有很多争论。
我知道最后几段似乎我正在进入一个兔子洞并将自己画到一个角落里,但这就是“appVersion 是 docker 标签并且无法通过命令行或值设置 appVersion”带我们去的地方。

@timothyclarke :对于您在此处描述的helm upgrade用例,您可能首先想做的是helm package ,它可以让您设置--version--app-version ,然后您可以helm install tarball,并将其作为 CI 工件保留,这增加了安装的可重复性,因为它不需要添加任何--set参数。 这就是我们的目标,尽管没有“通用图表”方面,因为我们的图表不是通用的。

这也是将构建元数据添加到Version的好机会,例如+g<shortCommitSHA>

根据#7517,这让我删除了一堆在安装到我们的 CI 测试集群之前重写 image.tag 的sed调用,然后在以后打包时再次调用。

这种方法实际上可能会解决大多数人在这里遇到的问题,如果他们正在构建自己的图表,特别是如果他们在结账时从图表源安装。 如果他们需要此功能来处理来自回购的图表,这并没有真正的帮助,但我认为这与这里的大多数人所遇到的问题不同?

对我来说,在安装时覆盖应用程序版本(或版本)的风险在于,其他人试图重新创建图表时,它并不是那么清晰可见,这已经完成。 除非它以某种方式侵入了值支持,否则当使用helm get values -o yaml提取图表的当前配置时它不会存在,因此它成为_另一件事_,使您的实时图表部署与您获得的不同helm install <some way to specify a particular package> --values <values from helm get values> ,例如,当尝试在测试设置上重现生产中出现的问题时。

对我来说,在安装时覆盖应用程序版本(或版本)的风险在于,其他人试图重新创建图表时,它并不是那么清晰可见,这已经完成。 除非它以某种方式侵入了值支持,否则当使用helm get values -o yaml提取图表的当前配置时它不会存在

你击中了要害。 这应该从第一天开始就在values.yml

虽然我理解反对这个功能的哲学论点,但现场实践表明它会帮助很多人——包括我们。

有很多图表可以让你通过values.yml设置应用程序的版本,特别是因为它不能在这里设置。

我不确定是否已经讨论过(快速 CTRL+F 并找不到任何痕迹),但是将appVersion全部删除作为替代解决方案怎么样? 在我看来,它会避免整个混乱。

现在appVersion被视为一种“特殊”值。 我假设,它可以提供可见性,例如我可以拥有 Prometheus 的图表版本 123.5.6,但它将具有 appVersion: 2.17.1,所以我知道它有什么安全补丁版本以及 Prometheus 的哪些功能值得期待,我可以使用helm ls查找。

我想这可以以某种不同的方式提供。 也许通过发布标签? 或者可能jsonPath查询所有版本,类似于kubectl可能的情况,例如:

kubectl get nodes -o jsonpath='{.items[*].status.addresses[?(@.type=="ExternalIP")].address}'

然后,对此的支持将转移到最佳实践,而不是由helm本身强制执行。 它也可以掉毛。

另一方面,可能很多人依赖于appVersion现有实现,这也需要考虑。

也许退后一步并理解为什么添加了appVersion将有助于解决这个问题?

@bokysan以前在values.yaml它已移至Chart.yaml我猜整个helm ls显示图表和 docker 标签,而不必运行这样的命令作为
kubectl get deployment <release name> -o jsonpath='{.spec.template.spec.containers[0].image}'

@TBBle我会解决你的每一点,但它会使这篇文章和上一篇一样长。 我认为这整个问题归结为某人仅通过查看公共存储库中的图表就认为通用图表不是有效用例。

一旦您需要开始使用 initContainers 和 sidecars,appVersion 的整个前提就变得毫无意义。 举一个现实世界的例子,我目前需要管理的项目之一是带有 php sidecar 的 nginx。 nginx 和 php 标签不经常更改。 php 容器/版本对于编写代码的开发人员来说非常重要。 更改最频繁的容器是提供内容的initContainer
我是否将appVersion设置为initContainer ,设置为php容器还是nginx ,并且仅选择其中之一会丢失哪些信息?

如果它对您的用户很重要,那么肯定应该是 PHP 版本? 那就是你的广告。 您也可以将所有三个都粘贴在您的 appVersion 中,毕竟它是一个自由文本字段。

如果您想强制使用appVersion == 容器图像标签,那么您会发现使用非平凡图表(即包含多个容器或没有容器的图表)会遇到挑战。 不过,这并不是真正的重点,或者它会是imageVersion 。 如果您要打包单个上游应用程序,请使用其版本。 如果您正在构建一个包含多个上游应用程序的包,请选择一个,例如 prometheus-operator's chart,或者忽略 appVersion,因为它是一个可选字段。

如果您的图表源是应用程序的_一部分,例如 Agones,只需将appVersion留空,或者如果您有依赖它的工具,则从version复制它。

这些事情都不需要是helm install时间的决定。 正如我之前提到的,除了“在安装时为第三方图表切换不同的上游版本”之外, helm package对于所有工作流程来说已经足够晚了,并且应该在--values--set与所有其他“在安装时更改 X”操作一样。

老实说,实际缺少的功能可能是“通过appVersion通过tpl ”,所以你可以把它读取.Values.image.tag或任何你的作品。

如果你想强制appVersion == 容器镜像标签

然后我们可能在https://github.com/helm/helm/issues/7517这可能是这一切的起源。

我完全不明白这个讨论。 为什么不让人们选择以他们认为最适合他们的方式使用应用程序版本是一个大问题?

在我目前的形式中,最好根本没有这个APP VERSION 。 它只会给我们项目中的人们带来混乱。 我们有超过 80 个使用相同舵图的服务,并且因为在helm upgrade -i ...无法轻松更改此APP VERSION helm upgrade -i ...我看到我们所有的应用程序将永远保留1.0在这里。 而且我不打算重新打包已经打包的图表来更改应用程序版本。 为什么我应该使我的 CI 复杂化以适合您的设计???

我也看到我只需要告诉大家不要使用helm list因为这对他们没有用。 要检查他们拥有我们的应用程序的哪个版本,他们需要使用其他东西。

开始阅读这篇谈话时我很乐观,但在看到你如何讨论这个以及你如何努力迫使用户采用你的思维方式后,我现在失去了希望:(。

helm listhelm history等中有两个不同的输出“CHART(version)”和“APP VERSION”非常有帮助,并且避免了深入研究命令行选项和输出解析以获得最重要的事实。

如果在构建时将“CHART(version)”和“APP VERSION”绑定在一起(“helm 包”),那么拥有两个不同值的全部好处就会有所损失。 构建图表并更新应用程序版本而不增加/更新图表版本将导致大麻烦,因为相同的图表版本会给您带来非常不同的结果。 :-<

所以现在我们被迫在每次发布时构建包,并同步增加“CHART(version)”和“APP VERSION”,以免陷入疯狂/不明朗的情况。

正如我刚刚了解到的,我们可以删除“APP VERSION”,因为它是可选的,并使用一些自定义值并使用它代替 {{ Chart.appVersion }} 用于我们的图像......但是然后helm list会信息量要少得多。 :-<

从用户(开发人员)的角度:

  • 能够在安装时设置一些版本属性/标志/值
  • 能够在带有标签“XX 版本”的 helm 列表/历史输出中查看该版本的属性/标志/值

我们有机会完成吗?

如果在构建时将“CHART(version)”和“APP VERSION”绑定在一起(“helm 包”),那么拥有两个不同值的全部好处就会有所损失。

我认为这是分歧的症结所在。 我使用 App 版本的好处是,正如当前设置所打算的那样,您知道包装应用程序的版本_用于该图表版本_,因为图表版本是整个图表的版本,而不是图表中模板的版本。 我不希望像“我们需要 Helm 图表的版本 ~XY”这样的每个语句都要求“哦,不要弄乱 AppVersion”添加到最后。

这个好处是失去了应用程序版本(和应用程序的实际版本)在安装时更改,因为现在图表版本不会告诉你你正在使用什么应用程序,并且你失去了使用 SemVer 来确保的能力,例如,您拥有最新但与 API 兼容的版本。

对于@pniederlag所描述的用例,能够让appVersion成为指向 Values 条目的模板将使helm list执行所需的操作,只要图表支持具有其应用程序版本(可能是容器标签)在安装时通过--set--values更改,就像其他“在安装时更改”配置选项一样。

在这里,我遇到了AppVersion

我们同时使用 Release 版本和 AppVersions。

现在要设置它们 - 我必须在helm package显式调用helm upgrade --install以创建一个本地 tar-archive,同时设置两个版本。

现在我要添加helm-secrets支持,并且...
它的包装器不能与helm package

所以现在怎么办?
放弃我们所有版本的支持和流程?
放弃使用 Secrets?
有任何想法吗?

实际上,这对于helm-secrets来说更像是一个问题,但它也与此处讨论的--set app-version能力有关,因为如果我可以以这种方式使用它 - 我不需要调用helm package

UPD哦,等等...我仍然可以使用helm secrets upgrade chart.tgz -f secrets.yaml ...
好的。
但是,+1 添加--set app-version

所以现在怎么办?
放弃我们所有版本的支持和流程?
放弃使用 Secrets?
有任何想法吗?

我们构建了两个包:一个只有图表的 helm 包,没有 env 值和机密文件。 我们将此包重命名为chart-{app-version}.tgz因为图表版本对我们来说毫无意义,图表版本也不支持我们的 app-version 语法。 我们的应用程序更新包括任何潜在的图表更新(相同的 repo,使用 git 标记)。

然后我们有第二个特定于环境的 tgz, chart-{app-version}-{env}.tgz包括图表 tgz、值 yaml 和加密的机密文件。 该文件还包括一个“package.yaml”,其中包含标签、应用程序和环境名称等值,供我们使用helm-secrets部署的自动化脚本使用。

我们习惯于使用语义版本号来标识我们的应用程序版本,或其中的大部分版本。 然后在 APP VERSION 中使用此编号在helm history列表中轻松识别它以进行回滚或其他操作。
由于系统不允许在部署时自动注入它,我们在部署命令之前在我们的 CI/CD 管道上自动执行这个简单的命令:

sed -i -E "s/^appVersion: (.*)/appVersion: ${deploy.project.version}/" ${chartPath}/Chart.yaml

这很棘手,但它按预期工作。

@bvis
您的解决方法的问题是您必须在 CI/CD 管道中编辑图表。
如果您使用集中式图表存储库,那么您将被迫使用helm pull repo/chart --untar

以编程方式注入 Chart.yaml/appVersion 的任何进一步进展? 有解决方法吗? 它将极大地推动 CI/CD Helm 。

@jakovistuk据我所知,使用 appVersion 显示容器版本的图表直接通过 Chart.yaml 执行此操作,例如nginx-ingress/Chart.yaml中所示...

我已经有一段时间没有过多考虑这个问题了,所以这可能是一个非常愚蠢的问题,但是有没有办法使用 Helm CLI 来覆盖 appVersion?

似乎这里的很多人都在寻求一种方法来覆盖“appVersion”字段。 此问题的原始意图/请求是允许 —app-version 替代 —version,因此用户可以运行“helm fetch —app-version=v0.15.0”,Helm 将计算出最新的图表版本将 v0.15.0 指定为 appVersion 并获取它。

在我们的项目/图表(cert-manager)中,我们希望让最终用户尽可能清楚他们正在安装哪个版本,因此允许他们按应用程序版本而不是图表版本进行安装将是一种更自然的安装体验。

也就是说,这个问题是在 2 年前打开的,从那以后我们选择只保持这两个版本号同步/锁定步骤。 这样做了几年后,它出奇的简单和轻松,尽管如果我们的部署清单发生变化,用户有时必须等待几周才能发布新的正式版本。

考虑到这个问题的年代,它的长度,种类繁多的略有不同的特征门,以及从那时起 Helm 项目的变化(Helm 3、OCI 图表等),我认为这个问题的状态不是很好以当前形式作为功能请求向前推进。 我准备关闭这个问题,但是其他有类似功能请求的人最好开一个新问题并链接到这个问题中的任何其他相关评论以提供证据。 希望这对 Helm 团队的分类流程更有效,以便您的请求能够获得所需的可见性!

我还认为这种功能可以,而且可能是最好的,作为外部工具或包装器实现
掌舵,尤其是在考虑到 OCI 更改时,我认为这会使实现起来更加棘手。

直到解决(或不解决)以下是我在 CI/CD (GitLab) 中解决此问题的方法:

使用 app-version 打包图表,然后部署它。
我知道 Chart 版本并不意味着与 appVersion 相同,但在我们的情况下,它可以作为一种解决方法。

deploy:
  image: alpine/helm:3.2.4
  stage: deploy
  environment:
    name: ${ENV}
  script:
    - helm package --app-version=${CI_COMMIT_TAG} --version=${CI_COMMIT_TAG} ${NAMESPACE}
    -  | 
       helm upgrade -i --wait ${CI_PROJECT_NAME} ./${NAMESPACE}-${CI_COMMIT_TAG}.tgz \
       --set image.repository="${CI_REGISTRY_IMAGE}" \
       --set image.tag="${CI_COMMIT_TAG}" \
       --set-string ingress.enabled="${INGRESS}" \
       --set service.port="${CONTAINER_PORT}" \
       --set service.targetPort="${CONTAINER_PORT}" \
       --set dc="${CI_ENVIRONMENT_NAME}" \
       --set project="${CI_PROJECT_NAME}" \
       --namespace ${NAMESPACE}
    - helm history ${CI_PROJECT_NAME} -n ${NAMESPACE}
  tags:
    - kubernetes
  only:
    - tags

如果你默认你的image.tag{{ .Chart.AppVersion }}那么你就不需要在安装过程中--set它,它已经是正确的。 这也适用于自动构建,当您的 Docker 镜像使用 SHA1 标记时,AppVersion 与 Docker 镜像标记匹配,并且版本是自动构建的 SemVer。

如果您的 AppVersion 恰好是 SemVer,则 Version 与 AppVersion 相同没有问题。

对于我的团队制作的包,我们正在转向寻找 AppVersion 的东西,例如 image.tag,如果未设置 AppVersion,则默认为 Version。 这不是一个巨大的差异,只是少了一个helm package标签版本的参数,但只有当您的图表是从与您要打包的东西相同的 SCM 构建的情况下才有意义。

如果您使用子图表设置图像标签, @TBBle将不起作用

您的意思是 image.tag 在子图表中,但您正在尝试使用父图表的版本吗? 如果是这样,是的,这非常尴尬,并且不容易管理。 我刚刚在https://github.com/googleforgames/open-match/的 Helm 图表中完全恢复了这种布局。 在这种情况下,我建议将有问题的子图表回滚到主图表中。

图表应该是独立隔离/可用的单位,而不是依赖于父图表行为来运行。 子图表有自己的版本,_that_ 是它的图像应该使用的版本,否则,为什么它是子图表?

在 Open Match 的情况下,子图表似乎被使用,以便XXX.enable可以用作 values.yaml 中的快捷方式来一次性禁用一堆东西,但随后它引入了一堆这样的结构性问题. Open Match 的子图表都大量使用名为模板的父图表,并且还有0.0.0-dev的本地版本,因此已经有两种代码味道,表明某些东西结构不好。

或者也许我误解了你的观察。

@haimari不幸的是,它不起作用(与 https://github.com/helm/helm/issues/6921 相关?):

> helm package $DIR/deployment/chart --app-version="1111e8" --version="3454e5" --namespace stage
Error: Invalid Semantic Version

但是,这有效:

> helm package $DIR/deployment/chart --app-version="0.0.0-1111e8" --version="0.0.0-3454e5" --namespace stage
Successfully packaged chart and saved it to: /Users/aws/service-0.0.0-3454e5.tgz

甚至这个(但看起来很脏):

> helm package $DIR/deployment/chart --app-version="0-1111e8" --version="0-3454e5" --namespace stage
Successfully packaged chart and saved it to: /Users/aws/service-0-3454e5.tgz

helm version version.BuildInfo{Version:"v3.4.0", GitCommit:"7090a89efc8a18f3d8178bf47d2462450349a004", GitTreeState:"dirty", GoVersion:"go1.15.3"}

我认为@haimari的解决方案原样仅有效,因为他们在 CI 管道中使用了与 semver 兼容的标签(即这将是为标记版本运行的作业的示例,而不是在每次提交时运行)

@a0s :我通常建议:

helm package $DIR/deployment/chart --app-version="<container image tag>" --version="<semver version>"

然后让你的容器图像标签值类似于{{ Values.image.tag | default .Chart.AppVersion | default .Chart.Version ,这样你就不需要像@haimari那样即时更改它。

在您的示例中,您有两个不同的 git 版本,对吗? 一个是容器镜像,一个是图表?

使用 SemVer,您不能真正将 git commit SHA 放入 semver 的有意义的部分,因为 semver 意味着排序,而 git commit SHA 是不可排序的。

所以你会想要使用类似0.0.1-alpha.<build-id>+g<gitcommitsha> ,其中<build-id>有点像来自 CI 系统的管道或作业 ID,所以它总是在你提交到你的项目中。 这样,当您需要时,您始终会获得最新版本。

在 SemVer 中,使用-意味着它是该版本的预发布版本,因此0.0.1-<anything>介于 0.0.0 和 0.0.1 版本之间。 +之后的部分是构建信息,排序时会忽略它,因此是放置 git SHA 或分支名称或其他不可排序的跟踪信息的好地方。

因此,对于您在此处使用的内容,如果其 SHA 恰好以2开头,例如0-2764e1 ,则0-3454e5似乎比下一次提交更新。

在您的示例中,您有两个不同的 git 版本,对吗? 一个是容器镜像,一个是图表?

是的,应用程序和图表 - 有两个独立的软件。

这样,当您需要时,您始终会获得最新版本。

如果我不想(甚至无法想象)要求最新的怎么办。

0.0.1-alpha.<build-id>+g<gitcommitsha>

这个字符串(插值后)似乎太长而无法放入标准helm list输出的一列中:)

我总是知道我要安装的应用程序的哪个版本(sha hash)(用--set args 传递它)。 而且我总是知道我使用的是哪个版本的图表(如@haimari所述,我将始终在我的 ci/cd 本地使用git checkout chart && helm pack && helm upgrade .tar.gz

什么可能出错?
1) 常规helm upgrade期间的错误。 好的,我将修复错误并重试(使用应用程序的另一个 sha 提交 - 99%)(或使用--atomic代替)
2) 手动回滚: helm rollback <RELEASE_NAME>或通过 CI/CD 部署之前的 sha 提交。

我错过了什么?

PS 老实说,我想在 version 和 app-version 中使用短 sha 部分仅供参考(在helm list

如果它只是为了提供信息,那么它会在 SemVer 中的+之后,而不是- 。 如果你_从不_关心发布的顺序,或者向任何人分发 Helm 图表,并且你的图表或应用程序还没有 SemVer,那么0+g<commitsha>是一个有效的 SemVer(相当于 0.0.0)。

例如,这就是 Open Match 的 Helm 自动构建图表所做的; 它们目前都是0.0.0-dev ,我们已经开始考虑制作0.0.0-dev+g<commitsha>以便如果您正在查看已安装的内容,您至少可以告诉 _which_ 主版本您拥有。

此页面是否有帮助?
0 / 5 - 0 等级