【问题标题】:How to update kubernetes deployment without updating image如何在不更新镜像的情况下更新 Kubernetes 部署
【发布时间】:2018-10-22 05:56:23
【问题描述】:

背景。

我们使用的是 k8s 1.7。我们使用 deployment.yml 来维护/更新 k8s 集群状态。在 deployment.yml 中,pod 的镜像设置为${some_image}:latest。创建部署后,只要有代码合并到 master,pod 的镜像就会更新为${some_image}:${build_num}

现在发生的情况是,假设我们是否需要修改 deployment.yml 中限制的资源并重新应用它。部署镜像也将更新为${some_image} :latest。我们希望保持镜像处于集群状态,而不是在 deployment.yml 中维护实际标签。我们知道文件中的replcas可以省略,默认取集群状态的值。

问题,

在 1.7 上,spec.template.spec.containers[0].image 是必需的。

  1. 是否也可以应用 deployment.yml 而不将图像更新为 ${some_image}:latest(类似 --ignore-image-change 的参数,或 deployment.yml 中的特定字段)?如果有,怎么做?

另外,我看到 1.10 documentation 中的图片是可选的。

  1. 是真的吗?如果有,从哪个版本开始?

--- 更新 ---

CI 在每次合并到主映像时构建和部署新映像。在部署时,CI 运行命令kubectl set image deployment/app container=${some_image}:${build_num},其中${build_num} 是管道的内部版本号。

要应用 deployment.yml,我们运行 kubectl apply -f deployment.yml

【问题讨论】:

  • 您能解释一下“由 CI 指定”是什么意思吗?如果我理解,您使用“最新”图像标签来保持最新状态,但有时您不希望“最新”提取最新图像?为什么不坚持使用适用于您的应用的标签,而不必担心图像的最新标签?
  • 你能链接到说 .spec.containers[].image 字段是可选的文档吗?
  • 我们使用 CI 来构建和部署镜像。在部署时,它运行 kubectl set image deployment/app container=image:tag,其中 tag 是内部版本号。 deploy.yml 中的内容无关紧要,一旦再次运行,它会更新部署的映像。和kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/… 这里它说这个字段是可选的,以允许更高级别的配置管理默认或......这让我想知道 1.10 是否像副本一样使其成为可选。

标签: kubernetes


【解决方案1】:

然而,在deployment.yml文件中,我们指定了镜像的最新标签,因为这个字段不可能保持最新

  • 使用“:latest”标签违反了 Kubernetes 部署中的最佳实践,原因有很多——回滚和版本控制就是其中的一部分。要正确解决此问题,您可能应该重新考虑 CI/CD 管道方法。例如,我们使用 ci-pipeline 或 ci-job 版本来标记图像。

是否可以在不将映像更新到指定文件的情况下更新部署。如果有,怎么做?

  • 要在不更改映像的情况下更新 pod,您有一些选项,每个选项都有一些限制,它们都需要一些 Ops 体操并引入额外的故障点,因为它违反了推荐的方法。
  • k8s 可以从您的 remote 注册表中提取图像(您必须跟踪哈希值,因为您的最新版本超出了您的直接控制 - 此处可能存在问题)。您可以在运行 pod 的节点的本地 docker 注册表上检查使用的哈希。
  • k8s 可以从 本地节点 注册表中提取图像(您必须确保在所有潜在节点上运行“:latest”的 pod 都在本地注册表的同一页面上才能正常工作 - 可能这里的问题)。到达那里后,您可以使用容器的 imagePullPolicy 以便在部署 CI 工具时 - 它使用 yaml 的应用(与创建相反)并将图像策略设置为始终,然后立即应用从不的图像策略(这里也是潜在问题) ,将拉取策略限制为已经拉取的图像到本地存储库(如前所述,这里也存在潜在问题)。
  • 以下是有关此方法的文档摘录: 默认情况下,kubelet 将尝试从指定的注册表中提取每个图像。但是,如果容器的 imagePullPolicy 属性设置为 IfNotPresent 或 Never,则使用本地图像(分别优先或独占)。 如果您想依靠预拉镜像来替代注册表身份验证,则必须确保集群中的所有节点都具有相同的预拉镜像。
  • 更多关于 k8s 如何处理图像以及为什么最新的标签可以咬回这里:https://kubernetes.io/docs/concepts/containers/images/

【讨论】:

    【解决方案2】:

    如果您不想在 CI 中处理 deployment.yaml 中的复杂语法,您可以选择使用模板处理器。例如mustache。它会稍微改变 CI 流程:

    1. 在模板配置 (env1.yaml) 中更新映像版本
    2. 从模板deployment.mustache和env1.yaml生成deployment.yaml
      $ mustache env1.yml deployment.mustache > deployment.yaml
    3. 将配置应用到集群。
      $ kubectl apply -f deployment.yaml

    主要好处:

    1. env1.yaml 始终包含最新的主构建映像,因此您正在使用正确的映像创建部署对象。
    2. env1.yaml 很容易在 CI 步骤更新或生成。
    3. deployment.mustache 保持不变,您确信在最终的 deployment.yaml 中可能发生的所有变化都是图像版本。

    还有许多其他模板渲染解决方案,以防 mustache 不适合您的 CI。

    【讨论】:

      【解决方案3】:

      和上面的 Const 一样,我强烈建议不要在任何 docker 镜像中使用 :latest,而是使用 CI/CD 来解决版本问题。

      我们在 Jenkins X 项目中遇到同样的问题,我们有许多 git 存储库,当我们更改库或基础 docker 映像等内容时,我们需要更改 pom.xml, package.json, Dockerfiles, helm charts 等中的许多版本。

      我们使用名为UpdateBot 的简单 CLI 工具自动在所有下游存储库上生成拉取请求。我们倾向于将其视为库和基础镜像的持续交付;)。例如这是current Pull Requests that UpdateBot has generated on the Jenkins X organisation repositories

      下面是我们在发布新的基础镜像时更新 Dockerfiles / helm 图表的方式: https://github.com/jenkins-x/builder-base/blob/master/jx/scripts/release.sh#L28-L29

      【讨论】:

        【解决方案4】:

        你知道repo.example.com/some-tag@sha256:... syntax 用于从 docker 注册表中提取图像吗?它几乎完全是为了解决您所描述的问题而设计的。


        从评论中更新

        你解决了错误的问题;该文件仅用于将内容加载到集群中——从那一刻起,元数据的权威副本就在集群中。 kubectl patch 命令可以是一种无需借助 sed(或更糟)即可更改某些内容的手术方式,但不应尝试在集群外维护集群状态

        【讨论】:

        • 你能说得更具体点吗?我不知道如何使用摘要引用图像可以避免在使用 deployment.yml 更新部署时更新图像。我们的 CI 在每次合并到 master 时构建和部署新镜像。文摘总是不同的。另外,为了让这更有趣,出于某种原因,我们必须使用打包程序...
        • 您的问题仍然很令人困惑,但是如果您的目标是更新Deployment,但要确保 当前 图像仍然在使用中,即使对于新创建的图像Pods,然后指定 @sha256pin 该图像,因为推送到:latest 的更多图像将永远(?)具有相同的哈希值。我强烈、强烈、强烈同意 :latest 是坏消息的另一个答案,但如果您的组织不能开始使用编号图像,那么 sha256 是最好的折衷方案
        • we have to use packer “必须”是一个非常强烈的短语,几乎可以肯定会让您遇到的任何问题变得更糟
        • 我们使用 deployment.yml 来维护部署。其中的图像:latest 更像是一个占位符(因为它是必需的)。部署镜像将由 CI 不断更新为:${build_num}。假设我只需要修改 deployment.yml 中限制的资源并再次应用它。部署映像也将更新为标记:latest。我们希望继续使用相同的标签,而不需要维护 deployment.yml 中的实际标签。你知道,在deployment.yml 中维护实际的标签是很困难的,因为我们每天要在一张图片上更改20+ build_num。
        • 我知道这是一个旧答案,但你能解释一下“但不应该尝试在集群外维护集群状态”.. 我不打算在没有某种方式的情况下将更改推送到集群跟踪这些更改,我可以通过版本化清单轻松管理这些更改。这似乎更好地遵循了不可变基础设施的理念。你存储你的kubectl patch 命令吗?你怎么知道你运行了什么命令?你完全依赖集群来提供面包屑?
        猜你喜欢
        • 2021-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-05
        • 2017-06-03
        • 2017-04-09
        • 2016-11-11
        相关资源
        最近更新 更多