bigywater.tech
Kubernetes · 102

ImagePullBackOff:原因分类与退避

Pod 卡在 ImagePullBackOff 到底是什么意思?怎么区分是网络问题、认证问题还是镜像根本不存在?kubelet 多久重试一次?这篇用一个假仓库制造四种拉取失败和一种配置错误,再把 330 秒里的重试节奏逐个记下来。

5 种
连接被拒绝 / 404 / 401 / DNS 失败 / 镜像名非法,message 各不相同
23 → 91 秒
拉取重试的间隔越来越长(23、24、55、91)
5 次
330 秒里的拉取尝试次数(事件里 Pulling 的次数)

先看 message,不要只看状态

实测 · 本机执行输出
  refused  localhost:5999/nolocal:1.0        → ErrImagePull;原因:仓库地址没有服务(连接被拒绝)
      message:failed to resolve reference "localhost:5999/nolocal:1.0": failed to do request: Head "https://localhost:5999/v2/nolocal/manifests/1.0": dial tcp [::1]:5999: connect: connection refused
  notfound localhost:5000/missing:1.0        → ErrImagePull;原因:仓库在线,镜像或 tag 不存在(404)
      message:rpc error: code = NotFound desc = failed to resolve reference "localhost:5000/missing:1.0": localhost:5000/missing:1.0: not found
  private  localhost:5000/private/app:1.0    → ErrImagePull;原因:需要认证(401)
      message:failed to resolve reference "localhost:5000/private/app:1.0": unexpected status from HEAD request to http://localhost:5000/v2/private/app/manifests/1.0: 401 Unauthorized
  nohost   nonexistent.invalid/app:1.0       → ErrImagePull;原因:域名解析失败
      message:failed to resolve reference "nonexistent.invalid/app:1.0": failed to do request: Head "https://nonexistent.invalid/v2/app/manifests/1.0": dial tcp: lookup nonexistent.invalid on <本机局域网IP>:53: no such host
  badname  busybox:1.36:extra                → InvalidImageName;原因:镜像名格式不对
      message:Failed to apply default image tag "busybox:1.36:extra": couldn't parse image name "busybox:1.36:extra": invalid reference format

在 worker 上用 hostNetwork Pod 跑了一个假的镜像仓库(localhost:5000:/v2/ 返回 200,名字里有 private 的返回 401,其余 manifest 返回 404),让五个 Pod 各撞上一种失败:localhost:5999 没有服务 → Head "https://localhost:5999/v2/nolocal/manifests/1.0": dial tcp [::1]:5999: connect: connection refused;localhost:5000/missing:1.0 → code = NotFound … not found;localhost:5000/private/app:1.0 → unexpected status from HEAD request to http://localhost:5000/v2/private/app/manifests/1.0: 401 Unauthorized;nonexistent.invalid/app:1.0 → lookup nonexistent.invalid … no such host;busybox:1.36:extra → InvalidImageName(couldn't parse image name … invalid reference format)。(在另一次运行里还看到:同一个 Pod 进入 ImagePullBackOff 后 message 变成 Back-off pulling image …: ErrImagePull: <真正的原因>,原因仍在后面。)

退避节奏

实测 · 本机执行输出
  Pod 创建后 330 秒内,容器状态变化(相对秒, reason):[(0, 'ContainerCreating'), (1, 'ErrImagePull'), (13, 'ImagePullBackOff'), (24, 'ErrImagePull'), (36, 'ImagePullBackOff'), (48, 'ErrImagePull'), (63, 'ImagePullBackOff'), (103, 'ErrImagePull'), (116, 'ImagePullBackOff'), (194, 'ErrImagePull'), (208, 'ImagePullBackOff')]
  每次出现 ErrImagePull(= 一次新的拉取尝试失败)的时刻:[1, 24, 48, 103, 194];相邻尝试的间隔(秒):[23, 24, 55, 91]
  假仓库日志里 missing/manifests/2.0 的请求共 6 条
  事件(去重后):[('BackOff', 21), ('Failed', 2), ('Failed', 3), ('Failed', 5), ('Failed', 21), ('Pulling', 5)]

对 localhost:5000/missing:2.0 观察 330 秒:容器状态依次是 ContainerCreating(0 秒)→ ErrImagePull(1)→ ImagePullBackOff(13)→ ErrImagePull(24)→ ImagePullBackOff(36)→ ErrImagePull(48)→ ImagePullBackOff(63)→ ErrImagePull(103)→ ImagePullBackOff(116)→ ErrImagePull(194)→ ImagePullBackOff(208)。每次出现 ErrImagePull 就是一次新的拉取尝试(事件里 Pulling 共 5 次),相邻尝试的间隔是 23、24、55、91 秒——越来越长,大致是 10、20、40、80 秒的退避再加上 kubelet 同步周期带来的十几秒抖动。修好问题之后,要等当前这一轮退避结束才会重试。

分步演示

ImagePullBackOff
本步的对象

    本文用到的工具与边界

    • 本机 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);假仓库是 worker 上的 hostNetwork Pod(python:3.12-alpine,http.server),containerd 通过 /etc/containerd/certs.d/localhost:5000/hosts.toml 用 HTTP 访问它;域名解析失败用 .invalid 域名;状态时刻来自每秒轮询 Pod 状态,单次测量,间隔会有一两秒误差;每种情形各一次
    • 没有验证:imagePullSecrets 提供凭证后 401 变成成功(下一篇);退避的上限 300 秒是否实际出现(本次只观察到 91 秒);并发拉取时 --serialize-image-pulls 造成的排队;镜像拉取失败时 Pod 的 phase 与 Ready 条件;私有仓库的 token 认证流程(401 + WWW-Authenticate)
    京ICP备2026067502号-1京公网安备11010502063487号