bigywater.tech
Kubernetes · 101

imagePullPolicy:IfNotPresent 与 latest

imagePullPolicy 的默认值是怎么来的?Always 是不是每次都下载整个镜像?仓库挂了时哪些 Pod 会受影响?同一个 tag 一定是同一份镜像吗?这篇用一个连不上的仓库和一个被改指向的 tag,把三种策略的行为都跑一遍。

latest → Always
不写 tag 或 tag 是 latest 时默认拉取策略;其他 tag 和 digest 是 IfNotPresent
ErrImagePull
镜像在本地但仓库连不上时,Always 的 Pod 的状态;IfNotPresent 与 Never 的 Pod 照常 Running
同 tag 不同镜像
IfNotPresent 只看 tag 在不在,不比较内容;同一节点上两个 Pod 的 imageID 不同

默认值

实测 · 本机执行输出
  image: busybox                                   → imagePullPolicy=Always
  image: busybox:latest                            → imagePullPolicy=Always
  image: busybox:1.36                              → imagePullPolicy=IfNotPresent
  image: busybox@sha256:aaaaaaaaaaaaaaaaaaaaaaaaa  → imagePullPolicy=IfNotPresent
  image: registry.example.com/team/app             → imagePullPolicy=Always
  规则:没写 tag 或 tag 是 latest → Always;指定了别的 tag 或 digest → IfNotPresent(由 API Server 的准入补上)

不写 imagePullPolicy 时,API Server 的准入按镜像引用补默认值:busybox(没写 tag)、busybox:latest、registry.example.com/team/app(没写 tag)是 Always;busybox:1.36(指定了别的 tag)和 busybox@sha256:…(digest)是 IfNotPresent。默认值是在创建对象时由准入写进 Pod spec 的,读出来就能看到。

仓库连不上时

实测 · 本机执行输出
  ifnp-present(localhost:5999/app:1.0 本地已有):容器状态 running;''
  never-present(localhost:5999/app:1.0 本地已有):容器状态 running;''
  always-present(localhost:5999/app:1.0 本地已有):容器状态 waiting/ErrImagePull;'failed to pull and unpack image "localhost:5999/app:1.0": failed to resolve reference "localhost:5999/app:1.0": failed to do request: Head "https://lo'
    always-present 的事件:['Pulling: Pulling image "localhost:5999/app:1.0"', 'Failed: Failed to pull image "localhost:5999/app:1.0": failed to pull and unpack image "localhost:5999/app:1.0": failed to resolve reference "localhost:5999/a', 'Failed: Error: ErrImagePull', 'BackOff: Back-off pulling image "localhost:5999/app:1.0"']
  对照:busybox:1.36(docker.io 的镜像,节点上有,但访问 docker.io 的连接不通也不拒绝)+ Always,过了 60 秒:容器状态 waiting/ImagePullBackOff,事件 ['Pulling: Pulling image "busybox:1.36"', 'Failed: Failed to pull image "busybox:1.36": rpc error: code = DeadlineExceeded desc = failed to pull and unpack image "docker.io/library/busybox:1.36": faile'](连接既不通也不被拒绝,要等超时才报错:DeadlineExceeded)

镜像 localhost:5999/app:1.0 在节点上已有,但这个仓库地址没有服务:IfNotPresent 和 Never 的 Pod 直接 Running;Always 的 Pod 容器状态是 ErrImagePull(failed to pull and unpack image … failed to resolve reference … Head "https://localhost:5999/…"),事件依次 Pulling、Failed、ErrImagePull、BackOff(Back-off pulling image),随后是 ImagePullBackOff。Always 并不是每次都下载整个镜像,但每次创建容器都要访问仓库确认 digest,仓库故障时这样的 Pod 起不来。对照 docker.io 的 busybox:1.36(节点上有,但连不通 docker.io)+ Always,60 秒后也是 ImagePullBackOff,事件里是 DeadlineExceeded——连接不通也不拒绝时要等超时才报错。

本地没有的镜像

实测 · 本机执行输出
  ifnp-missing(IfNotPresent + 本地没有):容器状态 waiting/ErrImagePull;message='failed to pull and unpack image "localhost:5999/missing:1.0": failed to resolve reference "localhost:5999/missing:1.0": failed to do request: Head "https://localhost:5999/v2/missing/manifests/1.0": di'
  never-missing(Never + 本地没有):容器状态 waiting/ErrImageNeverPull;message='Container image "localhost:5999/missing:1.0" is not present with pull policy of Never'
  对照:never-missing 的事件里没有 Pulling(Never 不会尝试拉取);ifnp-missing 的事件:['Pulling: Pulling image "localhost:5999/missing:1.0"', 'Failed: Failed to pull image "localhost:5999/missing:1.0": failed to pull and unpack image "localhost:5999/missing:1.0": failed to resolve reference "localhos', 'Failed: Error: ErrImagePull']

镜像 localhost:5999/missing:1.0 本地没有:IfNotPresent 会尝试拉取,失败 → ErrImagePull;Never 不拉取,直接 ErrImageNeverPull,message 是 Container image "localhost:5999/missing:1.0" is not present with pull policy of Never,事件里也没有 Pulling。

同一个 tag,不同的镜像

实测 · 本机执行输出
  节点上 demo:v1 原本是 busybox:第一个 Pod first 的 imageID=2b865bd036cfddd518839204
  在节点上把 demo:v1 这个 tag 改指向 nginx 镜像:docker.io/library/demo:v1
  第二个 Pod second 同样写 demo:v1 + IfNotPresent:imageID=8ba7c98b61c2a856a22b826a(不同:True)——没有拉取事件:无 Pulling
  first 里是 BusyBox v1.36.1 (2023-05-18 22;second 里是 nginx version: nginx/1.27.5——同一个 tag,同一个节点,两个 Pod 跑的是不同的镜像
  这就是为什么生产环境推荐固定 digest 或不可变 tag,而不是依赖 latest + Always 去“刷新”

节点上 demo:v1 原本是 busybox,Pod first 的 imageID 以 …2b865bd036cfddd518839204 结尾;用 ctr images tag --force 把节点上的 demo:v1 改指向 nginx 镜像后,第二个 Pod second 同样写 demo:v1 + IfNotPresent,没有任何拉取事件,imageID 是 …8ba7c98b61c2a856a22b826a。first 里是 BusyBox v1.36.1,second 里是 nginx/1.27.5。IfNotPresent 只看 tag 在不在,不比较内容;tag 是可变的,固定 digest 才能保证“跑的是同一份”。

分步演示

imagePullPolicy
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / kind(Docker 里的单节点或多节点真实集群,节点是 Docker Desktop 虚拟机里的容器)/ kubectl;用空的 kubeconfig 之外的独立 kubeconfig,不碰用户自己的集群;计时用 date +%s%N / kubectl 事件时间戳,数字每次运行会有小幅抖动。三节点 kind 集群 kx-main(Kubernetes v1.37.0,containerd v2.3.4),Pod 用 nodeName 固定在 worker;“localhost:5999”是不存在的仓库地址(连接立即被拒绝),镜像由 docker tag + kind load 放到节点上;访问 docker.io 的连接在这个环境里是黑洞(不通也不拒绝);改 tag 指向用节点上的 ctr -n k8s.io images tag --force;每种情形各一次
    • 没有验证:imagePullPolicy 在 initContainers / ephemeralContainers 上的行为;kubelet 的 --serialize-image-pulls 与 imagePullProgressDeadline;镜像拉取的 digest 校验(Always 时 manifest 未变就不下载层);ImagePullBackOff 的退避时间(下一篇);AlwaysPullImages 准入(见 k94);镜像垃圾回收对 IfNotPresent 的影响
    京ICP备2026067502号-1京公网安备11010502063487号