清醒地看着头盔2:“那就是……”

与其他解决方案一样,Helm-Kubernetes的软件包管理器-具有优缺点,因此在使用它时,您应该正确评估自己的期望...


我们在连续轧制工具库中使用Helm。 在撰写本文时,我们的集群中有超过一千个应用程序 ,并且这些应用程序中约有4000个安装有各种变体。 我们会定期遇到问题,但是总的来说,我们对解决方案感到满意,我们没有停机时间和数据丢失。

撰写本文的主要动机是为用户提供有关Helm 2主要问题的客观评估,而没有明确的结论,以及分享经验和我们的解决方案的愿望。

[BUG]推出后,群集中释放资源的状态与描述的Helm图不对应


在工作时,Helm不会考虑群集中释放资源的状态。 重新安装时,结果仅由当前和保存的配置确定。 因此,群集中的资源状态和Helm注册表不同,并且Helm并未考虑到这一点。

考虑一下这个问题如何表现出来:

  1. 图表上的资源模板对应于状态X。
  2. 用户安装图表(Tiller保存资源X的状态)。
  3. 接下来,用户手动更改群集中的资源(状态从X更改为Y)。
  4. 无需进行任何更改,它就可以进行helm upgrade ...并且资源仍处于状态Y,尽管用户期望X。

不仅如此。 在某个时候,用户更改了图表上的资源模板(新状态W)-在helm upgrade之后,我们有两种情况:

  • XW修补程序的应用正在下降。
  • 应用补丁后,资源进入状态Z,该状态与所需状态不对应。

为了避免这种问题,建议按以下方式组织与发行版的工作: 没有人应该手动更改资源 ,Helm是使用发行版资源的唯一工具。 理想情况下,图表更改应在Git存储库中进行版本控制,并在CD中应用。

如果此选项不合适,则可以监视发布资源状态的同步 。 手动同步可能看起来像这样:

  1. 我们通过helm get找出释放资源的状态。
  2. 通过kubectl get查找Kubernetes中资源的状态。
  3. 如果资源不同,那么我们将Helm与Kubernetes同步:
    1. 创建一个单独的分支。
    2. 更新图表清单。 模板必须与Kubernetes中的资源状态匹配。
    3. 我们执行部署。 我们在Helm注册中心和集群中同步状态。
    4. 之后,可以删除分支并继续正常工作。

当使用kubectl apply应用补丁时, kubectl apply所谓的3向合并 ,即 考虑更新资源的真实状态。 您可以在此处查看算法代码,并在此处阅读。

在撰写本文时,Helm开发人员正在寻找在Helm 3中实现三路合并的方法。对于Helm 2,事情并不那么乐观:不打算实现三路合并,但是有一个PR来确定创建资源的方式-您可以找到详细信息甚至参与作为相关问题的一部分。

[BUG]错误:找不到名称为NAME的资源


如果在重复部署时成功创建了新资源,则问题就会显现出来,并且部署本身最终会失败。 新资源表示图表上次安装中未包含的资源

如果推出失败,则该发行版将保存在标记为FAILED的注册表中,并且在安装过程中,Helm依赖于最新的DEPLOYED发行版的状态,在这种情况下,该发行版对新资源一无所知。 结果,Helm尝试重新创建这些资源,并失败,并显示错误“找不到名称为NAME的资源”(错误说的恰恰相反,但这是问题所在)。 问题的一部分是,Helm在创建补丁时没有考虑集群中发布资源的状态,如上一节所述。

目前,唯一的解决方案是手动删除新资源。

为了避免这种状态,如果命令最终失败,则可以自动删除在当前升级/回滚中创建的新资源。 在与Helm中的开发人员进行了长时间讨论之后,对于upgrade / rollback命令,添加了--cleanup-on-fail选项,该选项在推出失败时激活自动清洁。 我们正在讨论PR ,以寻求最佳解决方案。

从Helm 2.13版开始,-- --atomic选项出现在helm install/upgrade --atomic ,该--atomic在安装不成功时激活清理和回滚(有关更多详细信息,请参阅PR )。

[BUG]错误:直到超时之前手表关闭


当执行Helm挂钩时间过长(例如,在迁移期间)时,即使未超过指定Job的helm install/upgrade的指定超时和spec.activeDeadlineSeconds此问题。

该错误由Kubernetes API服务器在等待挂钩作业完成时生成。 Helm无法处理此错误并立即崩溃-而不是重试等待请求。

作为解决方案,您可以在api-server中增加超时:-- --min-request-timeout=xxx/etc/kubernetes/manifests/kube-apiserver.yaml文件中。

[BUG]错误:升级失败:“ foo”没有部署的版本


如果通过helm install的第一个版本失败,则后续的helm upgrade将返回类似的错误。

看来解决方案非常简单:首次安装失败后,您需要手动执行helm delete --purge ,但是此手动操作破坏了CI / CD的自动化。 为了不中断手动命令的执行,您可以使用werf功能推出 。 使用werf时,有问题的发行版将在重新安装后自动创建。

此外,从Helm 2.13开始,在helm installhelm upgrade --install只需指定--atomic选项,安装失败后,该发行版将自动删除( 有关详细信息,请参阅PR )。

自动回滚


Helm缺少--autorollback选项,该选项在--autorollback会记住当前成功的修订版本(如果上一个修订版本不成功,则会删除该版本),并且在尝试部署失败之后,将回滚到保存的修订版本。

由于产品无间断运行至关重要,因此有必要寻找解决方案,因此推出应该是可预测的。 为了最大程度地减少产品停机的可能性,通常使用具有多个轮廓 (例如,分段,质量保证和生产)的方法,该方法包括依次展开到轮廓。 通过这种方法,大多数问题都可以在正式投入生产之前得到解决,并且与自动回滚结合可以使您获得良好的结果。

要组织自动回滚,您可以使用helm-monitor插件,该插件可让您将回滚与Prometheus的指标绑定。 这里有一篇很好的文章介绍了这种方法。

对于我们的某些项目,使用了一种相当简单的方法:

  1. 在部署之前,我们记得当前的修订版(我们认为,在正常情况下,如果存在该发行版,则该发行版必然处于DEPLOYED状态):

     export _RELEASE_NAME=myrelease export _LAST_DEPLOYED_RELEASE=$(helm list -adr | \ grep $_RELEASE_NAME | grep DEPLOYED | head -n2 | awk '{print $2}') 
  2. 运行安装或升级:

     helm install/upgrade ... || export _DEPLOY_FAILED=1 
  3. 我们检查部署状态并回滚到保存状态:

     if [ "$_DEPLOY_FAILED" == "1" ] && [ "x$_LAST_DEPLOYED_RELEASE" != "x" ] ; then helm rollback $_RELEASE_NAME $_LAST_DEPLOYED_RELEASE fi 
  4. 如果部署不成功,我们将以错误结束管道:

     if [ "$_DEPLOY_FAILED" == "1" ] ; then exit 1 ; fi 

同样,从Helm版本2.13开始,在调用helm upgrade足以指定--atomic选项,并且在安装失败后将自动执行回滚( 有关详细信息,请参阅PR )。

在发布时等待发布资源的可用性和反馈


按照计划,Helm应该在使用--wait选项时监视相应的活动和就绪测试的执行情况:

 --wait if set, will wait until all Pods, PVCs, Services, and minimum number of Pods of a Deployment are in a ready state before marking the release as successful. It will wait for as long as --timeout 

此功能现在无法正常运行:不支持所有资源和所有API版本。 并且声明的等待过程本身不能满足我们的需求。

kubectl wait ,没有快速反馈,也没有办法调节这种行为。 如果部署失败,那么只有在超时之后我们才会知道。 如果安装出现问题,则必须尽早完成推出过程,翻转CI / CD管道,将发行版回退到工作版本,然后进行调试。

如果回退了有问题的发行版,并且在推出过程中Helm不返回任何信息,那么调试是什么? 在kubectl wait的情况下kubectl wait您可以组织一个单独的过程来显示日志,这将需要发行资源名称。 如何组织一个简单而有效的解决方案尚不清楚。 除pod日志外,有用的信息还可以包含在部署过程中,资源事件...

我们的werf CI / CD实用程序可以部署Helm图表并监视资源的可用性,并显示与推出有关的信息。 所有数据都合并到一个流中并发布到日志中。

此逻辑在单独的kubedog解决方案中进行。 使用该实用程序,您可以订阅资源并接收事件和日志,以及及时了解失败的部署。 即 作为解决方案,在不使用--wait选项的情况下调用helm install/upgrade后,可以为每个发行资源调用kubedog。

我们旨在制作一个工具,该工具将提供所有必要的信息,以便在CI / CD管道的输出中进行调试。 在我们最近的文章中了解有关该实用程序的更多信息。

也许有一天在Helm 3中会出现类似的解决方案,但到目前为止,我们的问题处于暂停状态。

默认情况下使用helm init时的安全性


默认情况下,执行helm init命令时,服务器组件将以与超级用户相似的特权安装在集群中,当第三方访问时,这可能导致不良后果。

为了确保群集的安全性,有必要限制Tiller的功能并注意连接-Helm组件之间通过其进行通信的网络的安全性。

第一个可以通过使用标准的Kubernetes RBAC机制来实现,该机制将限制分till器的操作,第二个可以通过设置SSL来实现。 在Helm文档中了解更多信息: 保护Helm安装

人们相信,服务器组件Tiller的存在是一个严重的体系结构错误 ,实际上是Kubernetes生态系统中具有超级用户权限的外来资源。 在某种程度上,我们同意:实现是不完善的,但让我们从另一端看一下 如果您中断部署过程并终止Helm客户端,则系统将不会保持未定义状态,即 分iller将使释放状态生效。 还需要了解,尽管Tiller在Helm 3中已被放弃,但这些功能仍将由CRD控制器执行。

火星人去模板


Go模板的入门门槛很高,但是该技术对DRY的功能和问题没有任何限制。 我们在Helm系列的上一篇文章中讨论了基本原理,语法,功能和运算符。

开箱即用的秘密


当它们位于一个位置时,可以方便地存储和维护应用程序代码,基础结构和部署模板。 秘密也不例外。

Helm不支持开箱即用的机密,但是可以使用helm-secrets插件,它实际上是sops ,Mozilla的机密管理器和Helm之间的一层。

在处理机密时,我们使用在werf中实现的自己的解决方案( 有关机密的文档 )。 的功能:

  • 易于实施。
  • 在文件中而不只是在YAML中保持机密。 存储证书,密钥时很方便。
  • 用新密钥重新生成秘密。
  • 没有秘密密钥的首次展示(使用werf时)。 对于开发人员没有此密钥但需要在测试或本地电路上启动部署的情况,这可能会很有用。

结论


Helm 2被定位为稳定的产品,但与此同时,许多错误悬而未决(其中一些可持续使用数年!)。 除了解决方案,或者至少是补丁程序,所有精力都在开发Helm 3上。

尽管MR和问题可能会挂起几个月( 这是我们如何before-hook-creation policy添加before-hook-creation policy 的示例 ,但持续了几个月的示例 ),但是您仍然可以参与项目的开发。 每个星期四,都会举行一个半小时的Helm开发人员集会,您可以在其中了解团队的优先事项和当前方向,提出问题并采取自己的最佳做法。 关于气象和其他沟通渠道的详细信息,请参见此处

当然,是否使用Helm取决于您。 今天,我们自己仍然坚持这样一种立场:尽管存在缺陷,但Helm是部署的可接受解决方案,它对整个社区参与其开发都是有用的。

聚苯乙烯


另请参阅我们的博客:

Source: https://habr.com/ru/post/zh-CN438814/


All Articles