如何强制 Kubernetes 重新拉取镜像?

Posted

技术标签:

【中文标题】如何强制 Kubernetes 重新拉取镜像?【英文标题】:How do I force Kubernetes to re-pull an image? 【发布时间】:2016-01-11 19:13:52 【问题描述】:

我在 GKE 上的 Kubernetes 中有以下复制控制器:

apiVersion: v1
kind: ReplicationController
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 2
  selector:
    app: myapp
    deployment: initial
  template:
    metadata:
      labels:
        app: myapp
        deployment: initial
    spec:
      containers:
      - name: myapp
        image: myregistry.com/myapp:5c3dda6b
        ports:
        - containerPort: 80
      imagePullPolicy: Always
      imagePullSecrets:
        - name: myregistry.com-registry-key

现在,如果我说

kubectl rolling-update myapp --image=us.gcr.io/project-107012/myapp:5c3dda6b

执行滚动更新,但不重新拉取。为什么?

【问题讨论】:

我给出了不同的图像,只是使用了相同的标签。如果有必要给出不同的标签,好吧,我在imagePullPolicy 字段中看不到任何意义。 我想使用一个特定的标签,但它是最新版本。 @TorstenBronger 我认为这是 Kubernetes/Docker 理论的重大变革。您可以在两个不同时间提取 image:tag(最新的除外)并获取两个不同的图像的想法是有问题的。标签类似于版本号。更好的做法是在图像更改时始终更改标签。 视情况而定。有些软件的 API 非常稳定,但有安全更新。然后,我想要最新的版本,而不必明确表示。 @TorstenBronger 关于使用latest,不要这样做。最新将使用最新标签提取最近的图像。你想要的是一个 SemVer 范围。以~1.2.3 为例。这将提取标签范围在 >= 1.2.3 和 SemVer,您就知道(这是重要的部分),就不会(故意)添加反向破坏性更改,也不会添加新功能(可能存在安全问题)。请不要在生产系统中使用latest 【参考方案1】:

如果有任何一种情况,Kubernetes 将拉动 Pod 创建(请参阅 updating-images doc):

使用标记为:latest 的图像 imagePullPolicy: Always 已指定

如果您想始终拉动,那就太好了。但是,如果您想按需执行此操作,该怎么办:例如,如果您想使用some-public-image:latest,但只想在您请求时手动拉取较新的版本。您目前可以:

imagePullPolicy 设置为IfNotPresentNeverpre-pull:在每个集群节点上手动拉取图像,以便缓存最新的图像,然后执行kubectl rolling-update 或类似操作以重新启动Pods(丑陋的容易破坏的黑客! ) 暂时更改imagePullPolicy,执行kubectl apply,重启pod(例如kubectl rolling-update),恢复imagePullPolicy,重做kubectl apply(丑陋!) 拉和推 some-public-image:latest 到您的私人存储库并执行 kubectl rolling-update(重!)

对于按需拉取没有好的解决方案。如果情况发生变化,请发表评论;我会更新这个答案。

【讨论】:

你说 kubernetes 会在使用 :latest 时拉动 Pod 创建 - patching 怎么样?它是否也总是拉最新/最新的图像?似乎不适合我:( 这取决于您的补丁是否强制重新创建 Pod。很可能不会,那么它就不会再次拉动。您可以手动杀死 Pod,或者使用独特的标签并使用更新后的标签进行修补。 这是对另一个问题的回答。我要求强制重新拉动。 这让我可以从 GCR 强制执行新的 pull。我有一个 :latest 标签指向一个新图像,kubectl rolling-update 用于更新 pod。 谢谢。采用 Pull & Push 方法。使用 bash 脚本尽可能多地自动化它,但同意,它很重:)【参考方案2】:

必须将imagePullPolicy 分组在容器数据中,而不是在规范数据中。但是,我为此提交了issue,因为我觉得这很奇怪。此外,没有错误信息。

所以,这个规范 sn-p 有效:

spec:
  containers:
  - name: myapp
    image: myregistry.com/myapp:5c3dda6b
    ports:
    - containerPort: 80
    imagePullPolicy: Always
  imagePullSecrets:
    - name: myregistry.com-registry-key

【讨论】:

imagePullPolicy(或标记:latest)如果你想总是拉,那很好,但不能解决按需拉的问题。 是的,我想总是拉,如问题中所述。 在容器定义中使用imagePullPolicy: Always 将有kubernetes 获取带有:latest 标记的图像,只要将更新版本的图像推送到注册表? @pkaramol No. imagePullPolicy: Always 只是告诉 Kubernetes 始终从注册表中提取图像。它将由image 属性配置什么图像。如果将其配置为image: your-image:latest,那么它将始终拉取带有latest 标签的your-image 图像。 我在这里遇到了与 cronjob 相同的问题。 “最新”标签被忽略,仅将作业规范设置为始终拉取策略使 k8s 为下一次执行(=容器创建)重新加载映像,这两个选项之间似乎有所不同,尽管每个文档都将它们视为平等。 【参考方案3】:

有一个命令可以直接做到这一点:

创建一个新的kubectl rollout restart 命令来滚动重启部署。

pull request 已合并。它是1.15 (changelog) 或更高版本的一部分。

【讨论】:

是问题的一部分:github.com/kubernetes/kubernetes/issues/13488 是的,这是在新的 kubernetes 1.15 版本中触发更新的最佳方式。 不,没有直接执行此操作的命令。这仅适用于 imagePullPolicy: Always 设置。 @spinkus 和 kubectl rollout restart deploy <name>【参考方案4】:

我在开发过程中的技巧是更改我的部署清单以添加最新标签并始终像这样拉

image: etoews/my-image:latest
imagePullPolicy: Always

然后我手动删除 pod

kubectl delete pod my-app-3498980157-2zxhd

因为是 Deployment,Kubernetes 会自动重新创建 pod 并拉取最新的镜像。

【讨论】:

我喜欢利用“部署”对象的“期望状态”前提...感谢您的建议! 值得注意的是,只有在服务故障和停机时间是可以容忍的情况下,策略才是可行的。对于开发来说,这似乎是合理的,但我永远不会将此策略用于生产部署。 编辑部署,将 imagePullPolicy 更改为 always 并删除 pod 对我来说就足够了,正如 Everett 建议的那样。虽然这是一个开发环境。 kubernetes.io/docs/concepts/containers/images【参考方案5】:

popular workaround 是使用虚拟注释(或标签)修补部署:

kubectl patch deployment <name> -p \
  "\"spec\":\"template\":\"metadata\":\"annotations\":\"date\":\"`date +'%s'`\""

假设您的部署 meets these requirements,这将导致 K8s 拉取任何新映像并重新部署。

【讨论】:

是的,我为此使用了注释。 什么注释? 另一个复杂的解决方案是两者的结合,即。添加注释并将ImagePullPolicy 设置为始终。像 deployment.kubernetes.io/revision: "v-someversion"kubernetes.io/change-cause: the reason 这样的注解可能会很有帮助,并且会朝着不可变的部署方向发展。【参考方案6】:

现在,kubectl rollout restart deploy YOUR-DEPLOYMENT 命令与 imagePullPolicy: Always 策略相结合,将允许您使用最新版本的映像重新启动所有 pod。

【讨论】:

【参考方案7】:
    将策略指定为:
  strategy: 
    type: Recreate
    rollingUpdate: null
    确保每个部署都有不同的注释。 Helm 喜欢:
  template:
    metadata:
      labels:
        app.kubernetes.io/name: AppName
        app.kubernetes.io/instance: ReleaseName
      annotations:
        rollme:  randAlphaNum 5 | quote 
    指定图像拉取策略 - 始终
      containers:
        - name:  .Chart.Name 
          image: " .Values.image.repository : .Values.image.tag "
          imagePullPolicy: Always

【讨论】:

【参考方案8】:
# Linux

kubectl patch deployment <name> -p "\"spec\":\"template\":\"metadata\":\"annotations\":\"date\":\"`date +'%s'`\""

# windows

kubectl patch deployment <name> -p (-join("\""spec\"":\""template\"":\""metadata\"":\""annotations\"":\""date\"":\""" , $(Get-Date -Format o).replace(':','-').replace('+','_') , "\"""))

【讨论】:

【参考方案9】:

此答案旨在在您的节点已经下载具有相同名称的图像的情况下强制执行图像提取,因此即使您将新图像推送到容器注册表,当您启动一些 pod 时,您的 pod 也会显示“图片已经存在”。

对于 Azure Container Registry 中的一个案例(可能 AWS 和 GCP 也提供了这个):

    您可以查看您的 Azure 容器注册表,通过检查清单创建日期,您可以确定哪个映像是最新的。

    然后,复制其摘要哈希(格式为sha256:xxx...xxx)。

    您可以通过运行以下命令来缩小当前副本。请注意,这显然会停止您的容器并导致停机。

kubectl scale --replicas=0 deployment <deployment-name> -n <namespace-name>
    然后你可以通过运行得到deployment.yaml的副本:
kubectl get deployments.apps <deployment-name> -o yaml > deployment.yaml

    然后将带有图像字段的行从&lt;image-name&gt;:&lt;tag&gt;更改为&lt;image-name&gt;@sha256:xxx...xxx,保存文件。

    现在您可以再次扩展您的副本。将提取新图像及其独特的摘要。

注意:假设容器中存在 imagePullPolicy: Always 字段。

【讨论】:

【参考方案10】:

显然,现在当您使用与现有容器映像相同的 --image 参数运行滚动更新时,您还必须指定 --image-pull-policy。当镜像与容器镜像相同时,以下命令应该强制拉取镜像:

kubectl rolling-update myapp --image=us.gcr.io/project-107012/myapp:5c3dda6b --image-pull-policy Always

【讨论】:

自 Kubernetes 1.18 起,此功能已被删除,如下所述:v1-18.docs.kubernetes.io/docs/setup/release/notes/#kubectl【参考方案11】:

您可以在部署文件中定义imagePullPolicy: Always

【讨论】:

适用于开发环境,但对于 prod 使用 rolligupdate 策略【参考方案12】:

通过了所有其他答案并且不满意,我在这里找到了更好的解决方案:https://cloud.google.com/kubernetes-engine/docs/how-to/updating-apps

它可以在不使用 latest 标签或 imagePullPolicy: Always 的情况下工作。如果您通过指定图像 sha256 摘要将新图像推送到同一标签,它也可以工作。

步骤:

    从 docker hub 获取图像 SHA256(见下图) kubectl set image deployment/&lt;your-deployment&gt; &lt;your_container_name&gt;=&lt;some/image&gt;@sha256:&lt;your sha&gt; kubectl scale deployment &lt;your-deployment&gt;--replicas=0 kubectl scale deployment &lt;your-deployment&gt;--replicas=original replicas count

注意:Rollout 也可以代替扩展,但在我的情况下,我们没有足够的硬件资源来创建另一个实例,并且 k8s 卡住了。

【讨论】:

小修正。在第二点,它应该是 而不是 【参考方案13】:

滚动更新命令,当给定图像参数时,assumes that the image is different 比复制控制器中当前存在的值。

【讨论】:

这是否意味着图像标签(又名)必须不同? 是的,如果你传递--image标志,图像名称必须不同。 正如我自己的回答所说,如果图像名称相同,它也可以工作。只是 imagePullPolicy 放错了地方。为了我的辩护,k8s 1.0 文档在这方面是错误的。 喜欢文档与行为不同步的情况。 :// 那个网址也过时了。【参考方案14】:

每次创建新 pod 时,图像拉取策略实际上总是有助于拉取图像(这在任何情况下都可以像缩放副本,或者 pod 死亡并创建新 pod)

但是如果要更新当前运行的 pod 的镜像,deployment 是最好的方式。它可以让您毫无问题地进行完美更新(主要是当您将持久卷附加到 pod 时):)

【讨论】:

【参考方案15】:

如果您想在特定 pod 上执行直接映像更新,您也可以使用 kubectl set image

https://kubernetes.io/docs/concepts/workloads/controllers/deployment/

【讨论】:

请添加更多详细信息以扩展您的答案,例如工作代码或文档引用。【参考方案16】:

您要么手动删除了所有 pod,以通过再次拉取映像来重新创建它。

在下面运行这个命令 kubectl rollout restart 部署/deployment_name kubectl rollout 重启部署/nginx

这个命令应该重新创建所有的 pod。

对于这两种情况,imagepullPolicy 应设置为 Always。

【讨论】:

以上是关于如何强制 Kubernetes 重新拉取镜像?的主要内容,如果未能解决你的问题,请参考以下文章

Kubernetes中部署Docker registry2.7.1并通过containerd实现拉取镜像到应用Pod的部署

kubernetes国内镜像拉取

[转帖]国内拉取google kubernetes镜像

国内拉取 gcr.io 镜像(Google Kubernetes 镜像)

快速解决Kubernetes从k8s.gcr.io仓库拉取镜像失败问题

【k8s】kubernetes实战篇之创建密钥自动拉取私服镜像