Helm 设备及其陷阱

Helm 设备及其陷阱
Typhon 货运概念车,安东·斯瓦内普尔 (Anton Swanepoel)

我叫 Dmitry Sugrobov,是 Leroy Merlin 的开发人员。 在本文中,我将告诉您为什么需要 Helm、它如何简化 Kubernetes 的使用、第三个版本中的更改以及如何使用它在生产中更新应用程序而无需停机。

这是根据会议演讲总结的 @Kubernetes 会议 by Mail.ru 云解决方案 - 如果您不想阅读,请观看视频。

为什么我们在生产中使用 Kubernetes

乐华梅兰 (Leroy Merlin) 是俄罗斯和欧洲 DIY 零售市场的领导者。 我们公司拥有一百多名开发人员、33 名内部员工以及大量的大卖场和网站访问人数。 为了让他们都满意,我们决定遵循行业标准方法。 使用微服务架构开发新的应用程序; 使用容器隔离环境并确保正确交付; 并使用 Kubernetes 进行编排。 使用编排器的价格正在迅速变得更便宜:市场上精通该技术的工程师数量在不断增长,并且供应商正在提供 Kubernetes 作为服务。

当然,Kubernetes 所做的一切都可以通过其他方式来完成,例如,通过使用脚本覆盖一些 Jenkins 和 docker-compose,但如果有现成的可靠解决方案,为什么还要让生活变得复杂呢? 这就是我们选择 Kubernetes 并在生产中使用它一年的原因。 我们目前有 XNUMX 个 Kubernetes 集群,其中最旧的已经有一年多了,有大约 XNUMX 个 pod。

Kubernetes 中大型 YAML 文件的诅咒

要在 Kubernetes 中启动微服务,我们将创建至少 XNUMX 个 YAML 文件:用于 Deployment、Service、Ingress、ConfigMap、Secrets,并将它们发送到集群。 对于下一个应用程序,我们将编写相同的门框包,对于第三个应用程序,我们将编写另一个,依此类推。 如果我们将文档数量乘以环境数量,我们将已经获得数百个文件,并且这尚未考虑动态环境。

Helm 设备及其陷阱
Helm 核心维护者 Adam Reese 介绍了“Kubernetes 中的开发周期”,看起来像这样:

  1. 复制 YAML - 复制 YAML 文件。
  2. 粘贴 YAML - 粘贴它。
  3. 修复缩进 - 修复缩进。
  4. 重复——再重复一遍。

该选项有效,但您必须多次复制 YAML 文件。 为了改变这个循环,Helm 被发明了。

什么是头盔

首先,头盔—— 包管理器,它可以帮助您找到并安装您需要的程序。 例如,要安装MongoDB,您不需要去官方网站下载二进制文件,只需运行命令 helm install stable/mongodb.

其次,头盔—— 模板引擎,有助于参数化文件。 让我们回到 Kubernetes 中 YAML 文件的情况。 编写相同的 YAML 文件更容易,向其中添加一些占位符,Helm 将在其中替换值。 也就是说,不再是一大堆脚手架,而是一组模板,所需的值将在适当的时候被替换到其中。

第三,头盔—— 部署大师。 使用它您可以安装、回滚和更新应用程序。 让我们弄清楚如何做到这一点。

Helm 设备及其陷阱

如何使用 Helm 部署自己的应用程序

我们来在电脑上安装Helm客户端,按照官方的说明 指示。 接下来,我们将创建一组 YAML 文件。 我们将保留占位符,而不是指定具体值,Helm 将在将来填充这些占位符。 一组此类文件称为 Helm 图表。 可以通过三种方式发送到Helm控制台客户端:

  • 指示带有模板的文件夹;
  • 将存档打包成 .tar 并指向它;
  • 将模板放入远程存储库中,并在 Helm 客户端中添加指向存储库的链接。

您还需要一个包含值的文件-values.yaml。 那里的数据将被插入到模板中。 我们也来创建它吧。

Helm 设备及其陷阱
Helm 的第二个版本有一个额外的服务器应用程序 - Tiller。 它挂在 Kubernetes 外部,等待 Helm 客户端的请求,当被调用时,将所需的值代入模板中并发送给 Kubernetes。

Helm 设备及其陷阱
Helm 3 更简单:信息现在完全在 Helm 客户端处理并直接发送到 Kubernetes API,而不是在服务器上处理模板。 这种简化提高了集群安全性并促进了部署方案。

它是怎么运行的

运行命令 helm install。 让我们指定应用程序版本的名称并给出values.yaml 的路径。 最后,我们将指出图表所在的存储库以及图表的名称。 在示例中,它们分别是“lmru”和“bestchart”。

helm install --name bestapp --values values.yaml lmru/bestchart

该命令只能执行一次,再次执行时会改为 install 需要使用 upgrade。 为简单起见,您可以运行以下命令,而不是两个命令 upgrade 带附加钥匙 --install。 第一次执行时,Helm 会发送安装该版本的命令,并在以后进行更新。

helm upgrade --install bestapp --values values.yaml lmru/bestchart

使用 Helm 部署新版本应用程序的陷阱

在故事的这一点上,我正在与观众一起玩《谁想成为百万富翁》,我们正在研究如何让 Helm 更新应用程序的版本。 看视频.

当我学习 Helm 的工作原理时,在尝试更新正在运行的应用程序的版本时,我对奇怪的行为感到惊讶。 我更新了应用程序代码,将新映像上传到 Docker 注册表,发送了部署命令 - 但什么也没发生。 以下是一些不完全成功的应用程序更新方法。 通过更详细地研究它们中的每一个,您开始了解仪器的内部结构以及这种不明显行为的原因。

方法 1. 自上次启动以来不要更改信息

俗话说 官方网站 Helm,“Kubernetes 图表可能很大而且很复杂,所以 Helm 尽量不要接触太多东西。” 因此,如果您在 docker 注册表中更新最新版本的应用程序镜像并运行命令 helm upgrade,那么什么也不会发生。 Helm 会认为没有任何变化,无需向 Kubernetes 发送命令来更新应用程序。

在这里和下面,最新标签仅作为示例显示。 当您指定此标签时,无论 imagePullPolicy 参数如何,Kubernetes 每次都会从 docker 注册表下载镜像。 在生产中使用最新版本是不可取的,并且会产生副作用。

方法2.更新图像中的LABEL

正如同中所写 文件资料,“Helm 只会更新自上次版本以来发生更改的应用程序。” 一个合理的选择似乎是更新 docker 镜像本身中的标签。 但是,Helm 不会查看应用程序映像,也不知道对它们进行的任何更改。 因此,当更新镜像中的标签时,Helm 不会知道它们,并且应用程序更新命令不会发送到 Kubernetes。

方法 3:使用密钥 --force

Helm 设备及其陷阱
让我们查阅手册并查找所需的密钥。 关键是最有意义的 --force。 尽管名称很明显,但其行为与预期不同。 其真正目的不是强制更新应用程序,而是恢复处于 FAILED 状态的版本。 如果不使用该键,则需要依次执行命令 helm delete && helm install --replace。 建议使用key代替 --force,它会自动顺序执行这些命令。 更多信息在此 拉取请求。 为了告诉Helm更新应用程序版本,不幸的是,这个键不起作用。

方法4.直接在Kubernetes中更改标签

Helm 设备及其陷阱
使用命令直接在集群中更新标签 kubectl edit - 馊主意。 此操作将导致正在运行的应用程序与最初发送用于部署的应用程序之间的信息不一致。 在这种情况下,Helm 在部署期间的行为与其版本不同:Helm 2 不会执行任何操作,Helm 3 将部署应用程序的新版本。 要了解原因,您需要了解 Helm 的工作原理。

头盔如何工作?

要确定应用程序自上次发布以来是否发生了更改,Helm 可以使用:

  • 在 Kubernetes 中运行应用程序;
  • 新的values.yaml和当前图表;
  • Helm 的内部发布信息。

更好奇的是:Helm 在哪里存储有关版本的内部信息?通过执行命令 helm history,我们将获取有关使用 Helm 安装的版本的所有信息。

Helm 设备及其陷阱
还有有关发送的模板和值的详细信息。 我们可以要求它:

Helm 设备及其陷阱
在 Helm 的第二个版本中,此信息位于 Tiller 运行的同一命名空间中(默认为 kube-system),在 ConfigMap 中,标有标签“OWNER=TILLER”:

Helm 设备及其陷阱
当 Helm 的第三个版本出现时,信息转移到秘密,并转移到应用程序运行的同一名称空间。 因此,可以在具有相同版本名称的不同命名空间中同时运行多个应用程序。 在第二个版本中,当名称空间相互隔离但又可以相互影响时,这是一个非常令人头痛的问题。

Helm 设备及其陷阱

第二个 Helm 在尝试了解是否需要更新时,仅使用两个信息源:现在提供给它的信息以及有关版本的内部信息(位于 ConfigMap 中)。

Helm 设备及其陷阱
第三个 Helm 使用三向合并策略:除了这些信息之外,它还考虑了 Kubernetes 中当前运行的应用程序。

Helm 设备及其陷阱
因此,旧版本的 Helm 将不会执行任何操作,因为它不考虑集群中的应用程序信息,但 Helm 3 将接收更改并发送新应用程序进行部署。

方法 5. 使用 --recreate-pods 开关

有钥匙 --recreate-pods 你可以用钥匙实现你原本计划实现的目标 --force。 容器将重新启动,并且根据 imagePullPolicy:始终针对最新标签的策略(更多内容请参见上面的脚注),Kubernetes 将下载并启动新版本的映像。 这不会以最佳方式完成:在不考虑部署的策略类型的情况下,它将突然关闭所有旧的应用程序实例并开始启动新的应用程序实例。 重启期间,系统将无法工作,用户将受到影响。

在 Kubernetes 本身,类似的问题也长期存在。 而现在,开业四年后 问题,该问题已得到修复,并且从 Kubernetes 1.15 版本开始,出现了滚动重启 pod 的功能。

Helm 只需关闭所有应用程序并在附近启动新容器即可。 您不能在生产中执行此操作,以免导致应用程序停机。 这仅是开发需要所需要的,并且只能在阶段环境中执行。

如何使用Helm更新应用程序版本?

我们将更改发送到 Helm 的值。 通常,这些是代替图像标签的值。 对于经常用于非生产环境的latest来说,可更改的信息是一个注释,这对于Kubernetes本身来说是无用的,而对于Helm来说,它将充当需要更新应用程序的信号。 填写注释值的选项:

  1. 随机值 使用标准函数 - {{ randAlphaNum 6 }}.
    有一个警告:每次部署使用具有此类变量的图表后,注释值将是唯一的,Helm 将假定存在更改。 事实证明,我们总是会重新启动应用程序,即使我们没有更改其版本。 这并不重要,因为不会出现停机,但仍然令人不快。
  2. 粘贴当前 日期和时间 - {{ .Release.Date }}.
    变体类似于具有永久唯一变量的随机值。
  3. 更正确的方法是使用 校验和。 这是图像的 SHA 或 git 中最后一次提交的 SHA - {{ .Values.sha }}.
    需要对它们进行计数并将其发送到调用方的 Helm 客户端,例如在 Jenkins 中。 如果应用程序已更改,则校验和将会更改。 因此,Helm 只会在需要时更新应用程序。

让我们总结一下我们的尝试

  • Helm 以侵入性最小的方式进行更改,因此 Docker 注册表中应用程序映像级别的任何更改都不会导致更新:执行命令后不会发生任何情况。
  • 关键 --force 用于恢复有问题的版本,与强制更新无关。
  • 关键 --recreate-pods 将强制更新应用程序,但会以破坏的方式进行:它会突然关闭所有容器。 用户会因此而受苦;你不应该在生产中这样做。
  • 直接使用命令对 Kubernetes 集群进行更改 kubectl edit 不要这样做:我们会破坏一致性,并且行为会根据 Helm 的版本而有所不同。
  • 随着 Helm 新版本的发布,出现了许多细微差别。 Helm 存储库中的问题以清晰的语言描述,它们将帮助您理解详细信息。
  • 向图表添加可编辑注释将使图表更加灵活。 这将使您能够正确推出应用程序,而无需停机。

“世界和平”思想适用于生活的各个领域:使用前而不是使用后阅读说明。 只有拥有完整的信息,才有可能构建可靠的系统并让用户满意。

其他相关链接:

  1. 满足 头盔 3
  2. 头盔官方网站
  3. GitHub 上的 Helm 存储库
  4. 25 个有用的 Kubernetes 工具:部署和管理

该报告首次发布于 @Kubernetes 会议 由 Mail.ru 云解决方案提供。 看 视频 其他表演并在 Telegram 上订阅活动公告 Mail.ru Group 围绕 Kubernetes 展开.

来源: habr.com

添加评论