镜像拉取策略由 imagePullPolicy 字段控制,必须显式配置在容器 spec 中;默认行为依标签而定:latest 为 Always,其余为 IfNotPresent。

直接结论:镜像拉取策略由 imagePullPolicy 字段控制,它不依赖全局配置,必须显式写在每个容器的 Pod/Deployment spec 中;默认行为取决于镜像标签 —— latest 默认为 Always,其他标签默认为 IfNotPresent。
什么时候必须显式设置 imagePullPolicy
很多人以为加了 latest 标签就自动每次都拉新镜像,但实际行为受默认策略和节点缓存双重影响。显式设置是唯一可靠方式:
- 你用的是非
latest标签(比如v1.2.3),但希望每次重启都强制更新镜像 → 必须设为Always - 你在离线环境或 CI 流水线中预加载了镜像,禁止任何网络拉取 → 必须设为
Never,否则会卡在ImagePullBackOff - 你部署到多节点集群,但某些节点没预热过镜像,又不想让
latest触发意外拉取 → 显式设为IfNotPresent可消除歧义
imagePullPolicy: Always 的真实行为不是“每次都下载”,而是“每次都校验摘要”
Kubelet 并不会无条件重下整个镜像。它会向仓库发起 HEAD 请求,比对远程镜像的 digest(如 @sha256:abc123...)和本地已存镜像的 digest。只有 digest 不一致时才触发下载。
- 如果你用
nginx:latest且仓库里latest指向的 digest 没变,Always实际不会拉取 - 但若你用
nginx:v1这种可变标签(tag 被覆盖过),Always仍会去校验并可能拉新 —— 所以更推荐用不可变 digest:nginx@sha256:... -
Always在私有仓库场景下还依赖认证是否就绪:如果imagePullSecrets缺失或过期,即使策略是Always,也会报ErrImagePull
IfNotPresent 在生产中最常踩的坑
这个策略看似安全,但容易掩盖两个关键问题:
- 节点上残留旧版镜像(比如上次部署留下的
myapp:v2.1),而你这次想部署v2.2,但 YAML 写错了标签(仍是v2.1)→ Kubelet 直接复用旧镜像,业务没更新却无任何提示 - 滚动更新时,新 Pod 调度到一个从未运行过该镜像的节点 → 第一次拉取阻塞启动,导致就绪探针失败、服务中断
- 使用
containerd时要注意:它的镜像缓存机制和docker不同,IfNotPresent对同一 tag 的多次拉取可能被内部 cache 拦截,但 digest 层面仍严格校验
私有仓库下 imagePullPolicy 和认证必须配对生效
策略本身不处理认证,只决定“要不要拉”。拉的动作能否成功,完全取决于 imagePullSecrets 是否可用、是否绑定正确:
- Secret 必须和 Pod 在同一 namespace;跨 namespace 引用无效
- Secret 类型必须是
kubernetes.io/dockerconfigjson,不能是 generic 类型 - 如果你用 ServiceAccount 绑定
imagePullSecrets,请确认 Deployment/Pod 没有覆盖serviceAccountName字段,否则绑定失效 - Harbor 等仓库启用了项目级权限时,Secret 中的
docker-server必须精确匹配仓库地址(如https://harbor.example.com,少https://或多/project都会失败)
最易被忽略的一点:当你把 imagePullPolicy 设为 Never 时,Kubelet 完全跳过认证检查 —— 即使 Secret 配错了也不会报错,但它会直接失败在 “no such image” 上,日志里连 ErrImagePull 都不会出现。这时候得去对应节点上手动执行 crictl images | grep your-image 确认镜像是否存在。


















