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

How do I force Kubernetes to re-pull an image?

我在 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

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

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

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

因此,此规范片段有效:

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

Kubernetes 将在创建 Pod 时执行以下任一操作(参见 updating-images doc):

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

如果你想一直拉,这很好。但是如果你想按需怎么办:例如,如果你想使用some-public-image:latest但只想在你要求时手动拉取较新的版本。您目前可以:

  • imagePullPolicy 设置为 IfNotPresentNeverpre-pull:在每个集群节点上手动拉取图像以便缓存最新的图像,然后执行 kubectl rolling-update 或类似于重新启动 Pods(丑陋且容易损坏的 hack!)
  • 临时 更改 imagePullPolicy,执行 kubectl apply,重新启动 pod(例如 kubectl rolling-update),还原 imagePullPolicy,重做一个kubectl apply(丑!)
  • 拉取和推送 some-public-image:latest 到您的私有存储库并执行 kubectl rolling-update(重磅!)

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

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

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

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

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

然后我手动删除pod

kubectl delete pod my-app-3498980157-2zxhd

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

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

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

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

有一个命令可以直接执行此操作:

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

pull request got merged. It is part of the version 1.15 (changelog) 或更高。

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

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

# 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('+','_') , "\""}}}}}"))

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

但是如果你想更新当前运行 pod的镜像,部署是最好的方式。它使您可以毫无问题地进行完美更新(主要是当您将持久卷连接到 pod 时):)

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

这个答案旨在在您的节点已经下载同名图像的情况下强制拉取图像,因此即使您将新图像推送到容器注册表,当您启动一些 pods,您的广告连播显示“图片已存在”。

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

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

  2. 然后,复制其摘要散列(格式为sha256:xxx...xxx)。

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

kubectl scale --replicas=0 deployment <deployment-name> -n <namespace-name>
  1. 然后你可以通过运行获得deployment.yaml的副本:
kubectl get deployments.apps <deployment-name> -o yaml > deployment.yaml
  1. 然后将带有图像字段的行从 <image-name>:<tag> 更改为 <image-name>@sha256:xxx...xxx,保存文件。

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

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

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

无需使用 latest 标签或 imagePullPolicy: Always 即可工作。如果您通过指定图像 sha256 摘要将新图像推送到同一标签,它也有效。

步骤:

  1. 从 docker 集线器获取图像 SHA256(见下图)
  2. kubectl set image deployment/<your-deployment> <your_container_name>=<some/image>@sha256:<your sha>
  3. kubectl scale deployment <your-deployment>--replicas=0
  4. kubectl scale deployment <your-deployment>--replicas=original replicas count

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

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

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

您是否已手动删除所有 pods 以通过再次拉取图像重新创建它。

运行 下面这个命令 kubectl 推出重新启动 deployment/deployment_name kubectl rollout restart deployment/nginx

此命令应重新创建所有 pods。

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