← 返回博客列表

registry.k8s.io 镜像拉不下来怎么办:kubeadm 初始化、ImagePullBackOff 与 containerd 镜像配置全解

2026-10-06 · 刺猬VPN

在国内搭 Kubernetes 集群,最先遇到的不是网络插件也不是证书,而是镜像。kubeadm init 在预检之后会拉取 kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、etcd、coredns 和 pause 一共七个镜像,默认地址都在 registry.k8s.io。这个域名背后会按请求来源重定向到不同云厂商的存储,从国内访问经常超时,终端里一行「pulling images」能停十几分钟,最后报「failed to pull image」和「context deadline exceeded」。

更麻烦的是,镜像问题不止出现一次。初始化时改了 kubeadm 的镜像仓库,容器运行时 containerd 却还有自己的一份 pause 镜像配置;控制面起来了,部署 ingress-nginx、metrics-server 这些组件时又会去拉 registry.k8s.io 上的其他镜像;新加入的工作节点又是一台没有缓存的干净机器。下面先讲清镜像的来源与几种获取方式,再按部署顺序给出步骤和报错对照。旧地址 k8s.gcr.io 已经冻结不再更新,新版本组件只发布在新地址上,以官方最新说明为准。

Kubernetes 镜像来源与几种获取方式

单机实验环境用「替换镜像仓库」最快;生产环境更推荐运行时代理或内部镜像仓库,因为它们不需要改动任何清单文件里的镜像地址,升级组件时也不用担心同步仓库缺版本。几种方式可以组合,比如控制面镜像走同步仓库、业务镜像走内部仓库。

方式原理优点局限
直连 registry.k8s.io通过线路访问官方仓库版本最全,与文档一致依赖线路质量
替换为国内同步仓库kubeadm 指定镜像仓库地址初始化快同步可能滞后,只覆盖常用镜像
containerd 镜像加速运行时层面把仓库映射到镜像站对所有 Pod 生效需要逐节点配置
运行时代理给 containerd 服务设置代理变量镜像地址不用改要处理好集群内网段排除
离线导入提前导出镜像包再导入节点不依赖外网版本升级要重新导出
内部镜像仓库Harbor 等仓库统一代理缓存团队共享、可审计需要维护一套服务

从初始化到部署组件:分步操作步骤

  • 第一步:先把网络线路准备好。在一台能连上刺猬VPN的机器上确认 registry.k8s.io 可以访问,客户端开全局模式时用 curl -I https://registry.k8s.io/v2/ 验证返回状态;服务器上如果不走全局线路,就给容器运行时单独配置代理,见第四步;
  • 第二步:列出要拉的镜像。执行 kubeadm config images list,加上 --kubernetes-version 指定版本,记下全部镜像名与标签,后面离线导入或核对同步仓库都要用到;
  • 第三步:用同步仓库初始化。在 kubeadm 的配置文件里写 imageRepository,或者在命令行加 --image-repository,常见的国内同步仓库是云厂商提供的 google_containers 命名空间,地址以其官方说明为准,然后执行 kubeadm config images pull 预拉取;
  • 第四步:给 containerd 配代理。在 systemd 的服务配置目录下为 containerd 新建一个代理配置片段,写入 HTTPS_PROXY 与 NO_PROXY,NO_PROXY 必须包含 localhost、节点网段、Pod 网段和 Service 网段,保存后执行 systemctl daemon-reload 并重启 containerd;
  • 第五步:修正 pause 镜像。打开 containerd 的配置文件,找到 sandbox_image 一项,把地址改成与 kubeadm 一致的仓库和版本号,重启 containerd,这一步漏掉是 Pod 卡在 ContainerCreating 的头号原因;
  • 第六步:配置镜像加速。在 containerd 配置里指定 config_path,然后在对应目录下为 registry.k8s.io、docker.io 分别建立 hosts.toml,写入镜像站地址,并保留官方地址作为后备;
  • 第七步:执行 kubeadm init,完成后用 crictl images 核对七个镜像都已就位,再安装网络插件;
  • 第八步:工作节点加入前,在每个节点上重复第四到第六步,或者把镜像离线导入,否则 kube-proxy 与网络插件的 Pod 会在新节点上拉取失败。

按现象排查:拉取、启动与组件部署

Kubernetes 的镜像报错会层层包装,先用 kubectl describe pod 看事件,再到节点上用 crictl 复现。

  • kubeadm init 报 failed to pull image 并带有 i/o timeout:控制面镜像拉不下来,确认线路或改用同步仓库;
  • Pod 一直 ContainerCreating,事件里有 failed to get sandbox image:containerd 的 pause 镜像地址没改,按第五步修正;
  • Pod 状态 ImagePullBackOff,事件里是 not found:同步仓库没有这个版本,换官方地址拉取或降低版本号;
  • Pod 状态 ErrImagePull,事件里是 x509 错误:镜像站证书不受信任,或公司网络替换了证书,在 hosts.toml 里配置证书或换镜像站;
  • 配置代理后集群内部通信失败,节点之间 Pod 无法访问:NO_PROXY 漏了 Pod 网段或 Service 网段,补齐后重启 containerd;
  • crictl pull 能成功但 Pod 仍然拉取失败:Pod 清单里的镜像地址与你拉的不完全一致,核对仓库前缀和标签;
  • Helm 装 ingress-nginx 时控制器镜像拉不下:图表里默认引用官方仓库,在 values 文件里覆盖镜像仓库地址,或走运行时代理。

几种方案怎么选

选择的核心是「以后怎么升级」。同步仓库省事,但新版本发布后可能要等一段时间才同步;运行时代理配置一次就和官方保持一致;离线导入适合完全隔离的环境,但每次升级都要重新打包。实际可用性取决于当前网络环境。

团队规模稍大时,比较稳妥的架构是在内网部署一套镜像仓库,开启对官方仓库的代理缓存功能,只有这台仓库服务器需要访问境外地址,所有节点的 containerd 都把镜像加速指向它。这样一来,同一个镜像无论多少台节点需要,都只从境外下载一次;仓库还会记录谁在什么时间拉了什么镜像,方便安全审计。仓库服务器本身的代理配置只需要维护一份,节点上不再需要任何代理变量,也就不存在网段排除写漏的问题。

对比项同步仓库运行时代理离线导入
配置成本低,一个参数中,逐节点配置高,每次升级重做
版本完整度常用版本齐全与官方一致只有导出的版本
对清单改动要改部分镜像地址无需改动无需改动
适合场景学习与实验集群长期运行的集群无外网的内网环境
线路需求不需要会员节点有效期内不限流量、不限速导出时需要一次
免费节点不涉及永久免费、不限流量、不限速,适合先验证可用于导出

本地开发集群的差别

minikube、kind、k3s 这些本地集群各有自己的镜像获取方式。minikube 启动时可以指定镜像仓库地址,节点镜像本身也要下载;kind 的节点是一个包含全部组件的容器镜像,第一次创建集群时要先拉下这个较大的节点镜像,之后的 Pod 镜像可以用 kind load 命令从本机直接导入集群;k3s 自带 containerd,镜像加速写在它自己的仓库配置文件里,而不是系统的 containerd 配置。

Docker Desktop 自带的 Kubernetes 则通过 Docker Desktop 的设置来配置代理,开启 Kubernetes 时会一次性拉取全部组件镜像,失败后界面会一直显示「Starting」。这种情况下先在 Docker Desktop 的「Resources」→「Proxies」里配置好代理,再重置 Kubernetes 集群,比反复点重试有效得多。

升级集群时的镜像检查顺序

这套顺序的意义在于把「拉镜像」从升级过程中剥离出来。升级本身只需要几分钟,真正耗时且容易失败的是镜像拉取,提前做完就能把风险集中在可控的时间段处理。生产集群建议先在测试集群完整演练一遍,记录每一步用到的镜像与命令,再照着清单操作。

  • 先查清单:用新版本号执行一次镜像列表命令,与当前版本对比,找出这次升级新增或变更的镜像,通常是控制面四个组件、coredns 和 pause;
  • 再查来源:逐个确认这些镜像在你的来源里能拉到,同步仓库要特别留意新版本是否已经同步,可以先在一台节点上用 crictl pull 试拉;
  • 然后预拉:在每个节点上提前把新版本镜像拉好,控制面节点执行预拉命令,工作节点至少把 kube-proxy 与 pause 拉好,升级时就不会因为拉取超时卡住;
  • 接着改配置:如果 pause 镜像的版本号变了,同步修改 containerd 的 sandbox_image 并重启,否则升级完成后新建的 Pod 会卡在创建阶段;
  • 最后升级:按先控制面、后工作节点的顺序逐台升级,每台完成后用 kubectl get nodes 确认状态为 Ready,再处理下一台;
  • 顺手清理:升级稳定运行几天后,用 crictl rmi 清掉旧版本镜像,避免节点磁盘被历史镜像占满。

与容器工具的分工

Kubernetes 只解决 registry.k8s.io 上的组件镜像,业务镜像多数还在 Docker Hub,匿名拉取的频率限制、镜像加速器失效等问题见 Docker Hub 访问与拉取限制。本地构建和调试镜像时选 Docker 还是 Podman,二者对代理和镜像仓库配置文件的写法不同,见 Podman 与 Docker 怎么选。

层次是这样的:构建工具负责把镜像做出来,镜像仓库负责存放与分发,containerd 负责在节点上拉取与运行。配置代理和镜像站时,三层各有各的配置文件,改哪一层要先想清楚。

常见报错速查表

现象原因解决办法
failed to pull image 加 i/o timeout官方仓库不可达走线路或改用同步仓库
failed to get sandbox imagepause 镜像地址未改修改 sandbox_image 后重启
ImagePullBackOff 加 not found同步仓库缺版本换官方地址或调整版本
ErrImagePull 加 x509镜像站证书不受信任配置证书或更换镜像站
Pod 跨节点不通NO_PROXY 漏了网段补齐 Pod 与 Service 网段
context deadline exceeded拉取超时检查线路后重试
Docker Desktop 一直 Starting组件镜像拉取失败配置代理后重置集群

高频问答

  • 问:k8s.gcr.io 还能用吗?答:旧地址已冻结,不再发布新版本,新部署统一用 registry.k8s.io,以官方最新说明为准;
  • 问:只改 kubeadm 的镜像仓库够吗?答:不够,containerd 的 pause 镜像和后续组件的镜像都要单独处理;
  • 问:同步仓库安全吗?答:镜像带有摘要,可以和官方摘要核对,生产环境建议用内部仓库统一代理;
  • 问:代理会不会影响集群内部通信?答:NO_PROXY 写全节点、Pod 与 Service 网段就不会;
  • 问:离线导入用什么命令?答:在有网络的机器上导出镜像包,在节点上用 ctr 指定 k8s.io 命名空间导入;
  • 问:升级集群要注意什么?答:先确认新版本的镜像在你的镜像来源里都能拉到,再执行升级,并且提前在每个节点上预拉好镜像,避免升级过程中因为拉取超时而中断,具体顺序见上文的检查清单。

让集群镜像来源长期稳定

registry.k8s.io 镜像拉不下来,本质是集群里有三四个地方各自在拉镜像:kubeadm 的控制面、containerd 的 pause、组件清单与业务 Pod。把这几处统一指向同一个来源,要么同步仓库,要么运行时代理加镜像加速,要么内部仓库,ImagePullBackOff 和 ContainerCreating 就不会反复出现。新节点加入前用脚本统一下发配置,比事后逐台排查省力得多。

刺猬VPN 支持自定义用户名和密码匿名注册,不需要邮箱、也不需要手机号,采用 HTTPS+AES 加密传输;免费节点永久免费、不限流量、不限速,适合先验证 registry.k8s.io 是否可达;时长套餐有效期内不限流量、不限速,适合经常拉取镜像、导出离线包的运维与开发人员,一个账号支持多设备同时在线。客户端带断线保护和按域名、IP 的智能分流,国内镜像站照常直连。实际可用性取决于当前网络环境。

立即下载刺猬VPN:从注册到连接,三分钟完成

刺猬VPN提供永久免费节点,不限流量;无需邮箱,自定义用户名即可匿名注册。一个账号支持多设备同时在线,实际可用性取决于当前网络环境。