在 Kubernetes 中,容器镜像的拉取行为并不由节点上是否已经存在镜像单独决定,而是由 Pod 规范中的 imagePullPolicy 字段显式控制。该字段定义了 kubelet 在创建容器时如何从镜像仓库获取镜像,取值可以是 Always、IfNotPresent 或 Never。理解这三种策略的默认逻辑,对保证应用发布的一致性和避免启动失败至关重要。

imagePullPolicy 直接作用于每一个容器的镜像拉取阶段。即使两个容器使用相同镜像,只要策略不同,Kubernetes 调度到同一节点后也可能触发不同的仓库请求。接下来从取值语义、默认规则以及生产环境常见问题几个方面详细展开。
imagePullPolicy 的三种取值与默认规则
imagePullPolicy 支持三种取值。Always 表示每次创建 Pod 时都向镜像仓库发起拉取请求,即使节点本地已经存在相同的镜像名称和标签,也会检查远端仓库;IfNotPresent 表示仅当节点本地不存在指定镜像时才从仓库拉取,如果本地已有缓存则直接使用;Never 表示完全禁止自动拉取,节点上必须事先存在对应镜像,否则容器会启动失败。
当 Pod 或 Deployment 中没有显式设置 imagePullPolicy 时,Kubernetes 会根据镜像标签自动推断。如果镜像标签是 latest,或者镜像名称中完全没有指定标签,例如只写了 nginx,那么默认策略会变为 Always。如果指定了明确的非 latest 标签,例如 nginx:1.25.3,则默认策略为 IfNotPresent。这一规则容易被忽略,很多团队在测试环境写 nginx 时没有显式声明策略,结果每次创建 Pod 都会向 Docker Hub 发起请求,遇到限流后出现拉取失败。
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
containers:
- name: app
image: nginx:1.25.3
imagePullPolicy: IfNotPresent
- name: sidecar
image: busybox:latest
imagePullPolicy: Always
从上面示例可以看出,同一个 Pod 的不同容器可以拥有不同的拉取策略。第一个容器使用具体版本标签并显式指定 IfNotPresent,节点已有 nginx:1.25.3 时就不会访问仓库;第二个容器使用 latest 标签并指定 Always,即使节点已经有 busybox:latest,kubelet 仍然会尝试从仓库拉取最新内容。这种组合在应用主容器与辅助容器之间很常见,但需要明确各自行为,避免误判。
latest 标签的隐患与镜像标签规范
latest 标签在 Kubernetes 中非常容易引发问题。它并不是一个不可变标签,镜像仓库允许 latest 指向任意一次构建结果。如果部署时没有指定其他标签,同一份 YAML 在不同时间执行可能拉取到完全不同的镜像,导致滚动更新过程不可控。更麻烦的是,不同节点上的 latest 镜像缓存可能不一致,因为每个节点是否拥有旧缓存取决于历史调度情况,最终会出现同一个 Deployment 中部分 Pod 运行新版本、部分 Pod 运行旧版本的割裂状态。
生产环境强烈建议使用不可变标签,例如语义化版本号或 Git Commit SHA。持续集成完成构建后,将镜像推送到仓库时打上唯一标签,并在 Kubernetes 资源配置中引用该标签。这样可以保证每次部署内容确定,同时配合 IfNotPresent 提高启动速度,因为节点只需要在首次拉取时访问仓库。下面是一个推荐写法。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: registry.ipipp.com/web:v1.4.2
imagePullPolicy: IfNotPresent
如果团队出于调试目的必须使用 latest 标签,建议显式设置 imagePullPolicy 为 Always,以确保每次创建 Pod 都能获取最新镜像。但这种做法会增加仓库访问频率,还可能受到 Docker Hub 等公共仓库的速率限制。更好的替代方案是在每次构建时生成唯一标签,这样既不用依赖 latest 的变动语义,也能保持镜像来源清晰可追溯。
私有镜像仓库与 imagePullSecrets
拉取私有镜像仓库中的镜像时,Kubernetes 需要携带认证信息。认证信息存储在 Secret 对象中,类型为 kubernetes.io/dockerconfigjson。可以通过 kubectl create secret docker-register 命令从命令行参数直接生成,也可以从本机 Docker 配置文件导入。创建完成后,在 Pod 或 Deployment 中通过 imagePullSecrets 字段引用。
kubectl create secret docker-registry regcred \ --docker-server=registry.ipipp.com \ --docker-username=admin \ --docker-password=secret \ --docker-email=admin@ipipp.com \ -n production
上述命令会在 production 命名空间下创建名为 regcred 的 Secret,其中包含访问 registry.ipipp.com 所需的账号密码。需要注意的是,Secret 是命名空间级资源,同一个 Secret 不能跨命名空间使用,如果多个命名空间都需要访问同一私有仓库,必须在每个命名空间分别创建。也可以在 Pod 规范中引用不同的 Secret,以应对多个私有仓库并存的情况。
apiVersion: v1
kind: Pod
metadata:
name: private-pod
namespace: production
spec:
imagePullSecrets:
- name: regcred
containers:
- name: app
image: registry.ipipp.com/team/app:v2.0.1
imagePullPolicy: IfNotPresent
除了在每个 Pod 中重复声明 imagePullSecrets,还可以把凭证绑定到 ServiceAccount。通过给 default 或其他 ServiceAccount 打补丁,可以让使用该 ServiceAccount 的 Pod 自动附加镜像拉取凭证,减少配置重复。命令示例如下。
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}' -n production
这样做之后,该命名空间下未显式指定 ServiceAccount 的 Pod 也会自动挂载 regcred。需要提醒的是,为 default ServiceAccount 自动附加凭证会作用于所有新建 Pod,如果某些 Pod 不需要私有仓库权限,也可能因此无意中携带访问凭证,安全上需要谨慎评估。更精细的做法是创建专用 ServiceAccount,并只给需要访问私有仓库的工作负载使用。
容器运行时差异与拉取失败排查
Kubernetes 从 1.24 版本开始移除了 dockershim,节点上的容器运行时通常使用 containerd 或 CRI-O。Docker 镜像本身遵循 OCI 标准,所以 containerd 可以直接拉取 Docker 构建的镜像,但节点上 Docker 命令看到的本地镜像与 containerd 的镜像存储并不共享。如果运维人员习惯用 docker images 检查节点镜像,却看到 Kubernetes 仍然报镜像拉取失败,很可能就是运行时不同导致误解。此时应改用 crictl images 查看实际供 Kubernetes 使用的镜像存储。
当 Pod 状态长时间处于 ImagePullBackOff 或 ErrImagePull 时,首先通过 kubectl describe pod 查看 Events 中的具体错误信息。常见原因包括镜像标签不存在、仓库域名无法解析、认证失败或节点磁盘空间不足。可以进一步在节点上执行 crictl pull 来验证运行时是否能单独拉取该镜像,从而判断问题出在 Kubernetes 层面还是运行时或网络层面。
kubectl describe pod private-pod -n production | tail -20 crictl images | grep web crictl pull registry.ipipp.com/team/app:v2.0.1
如果 crictl pull 也失败,需要检查节点到仓库的网络连通性,以及 containerd 配置文件中的镜像仓库 TLS 配置。containerd 的认证和镜像仓库配置位于 /etc/containerd/config.toml,与早期 Docker daemon 的配置位置不同。私有仓库使用自签名证书时,需要在 containerd 中正确配置证书路径,否则即使 Secret 正确也无法建立安全连接。对于集群管理员来说,理解运行时差异可以大幅缩短镜像拉取故障的定位时间。
总结而言,imagePullPolicy 看似只有三个取值,但它与镜像标签、私有仓库凭证、运行时存储以及网络环境紧密相关。选择 IfNotPresent 能提升启动效率,但需要保证标签不可变;选择 Always 能避免缓存不一致,却会带来额外流量和限流风险。将策略与镜像标签规范、Secret 管理以及运行时特点结合起来,才能在 Kubernetes 中稳定高效地拉取 Docker 镜像。
Kubernetes镜像拉取策略Docker修改时间:2026-08-23 16:34:07