纯技术分享,无商业合作。
凌晨被叫醒:线上 K8s 集群镜像全挂了
上周四凌晨 2 点,电话响了------线上 K8s 集群 ImagePullBackOff 红了一整屏。containerd 日志全是 i/o timeout,之前配的几个镜像加速地址全失效了,Node 直连 registry.k8s.io,超时是必然的。
更坑的是:很多运维搜到的教程都是 Docker 的 registry-mirrors,改到 containerd 上根本不生效。这两套配置完全不一样。
技术群里最近一个月大量类似求助:
- "K8s 1.30 升级后镜像拉不下来,containerd 怎么配?"
- "CI/CD 里
ctr images pull一直超时..." - "kubeadm init 卡在拉镜像,怎么办?"
这篇文章把实测有效的 5 种方案整理出来,附带数据对比和自动化脚本。
⚠️ Docker 配置 ≠ containerd 配置
| Docker | containerd | |
|---|---|---|
| 配置文件 | /etc/docker/daemon.json |
/etc/containerd/config.toml |
| 加速方式 | registry-mirrors |
registry.configs + mirrors |
| 重启命令 | systemctl restart docker |
systemctl restart containerd |
| 镜像操作 | docker pull |
ctr -n k8s.io images pull |
⚠️ 关键: containerd 有命名空间概念,K8s 的镜像是 k8s.io 命名空间,用 ctr images pull(默认命名空间)拉的镜像 K8s 看不到!
5 种方案实测对比
方案一:直接改 containerd 配置
toml
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://加速源地址"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://加速源地址/k8s"]
bash
systemctl daemon-reload && systemctl restart containerd
ctr -n k8s.io images pull docker.io/library/nginx:alpine # 验证
✅ 生效快,对 K8s 透明 | ❌ 每个 Node 单独配置,免费源频繁失效
方案二:自建 Registry 代理(Harbor / Registry)
bash
docker run -d -p 5000:5000 \
-e REGISTRY_PROXY_REMOTEURL=https://registry-1.docker.io \
--name registry-proxy registry:2
# containerd mirrors 指向 http://内网IP:5000
✅ 拉一次就缓存,后续极快 | ❌ 需要维护额外服务器
方案三:CF Worker 反代
javascript
export default {
async fetch(request) {
const url = new URL(request.url);
const registry = 'https://registry-1.docker.io';
const target = registry + url.pathname + url.search;
return fetch(new Request(target, { method: request.method, headers: request.headers }));
}
};
✅ 全球 CDN,延迟低 | ❌ 100MB+ 镜像层经常中断,2026 年 CF 限制更严了
方案四:国内第三方加速服务
| 服务 | 速度 | 稳定性 | K8s 支持 |
|---|---|---|---|
| 毫秒镜像 | 10-20 MB/s | 高 | ✅ |
| DaoCloud | 5-10 MB/s | 中 | ⚠️ 部分支持 |
| 百度云加速 | 3-8 MB/s | 中 | ❌ 仅 Docker |
toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://加速服务地址"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://加速服务地址/k8s"]
✅ 配置最简单,开箱即用 | ❌ 免费额度可能有限
方案五:nerdctl 预拉取 + 私有仓库
bash
# 安装 nerdctl
curl -sSLO https://github.com/containerd/nerdctl/releases/download/v2.0.2/nerdctl-2.0.2-linux-amd64.tar.gz
tar -xzf nerdctl-2.0.2-linux-amd64.tar.gz && mv nerdctl /usr/local/bin/
nerdctl pull --namespace k8s.io 加速源/library/nginx:alpine
nerdctl tag --namespace k8s.io 加速源/library/nginx:alpine nginx:alpine
nerdctl push --namespace k8s.io nginx:alpine 私有仓库/nginx:alpine
✅ 灵活可控,适合 CI/CD | ❌ 需要脚本自动化
📊 实测数据
环境: 腾讯云 2C4G,安徽节点
拉取 nginx:latest(190MB):
| 方案 | 速度 | 耗时 | 成功率 |
|---|---|---|---|
| 直连 Docker Hub | 50-200 KB/s | 15-30min | 30% |
| 自建 Registry | 5-15 MB/s | 15-30s | 85% |
| CF Worker | 2-8 MB/s | 30-90s | 60% |
| 国内加速服务 | 10-20 MB/s | 10-20s | 95% |
| nerdctl 预拉取 | 取决于源 | - | 90% |
拉取 pytorch/pytorch:2.2.0-cuda12.1(8GB,AI 训练场景):
| 方案 | 速度 | 耗时 |
|---|---|---|
| 直连 | - | ❌ 超时失败 |
| 国内加速服务 | 12-18 MB/s | 8-12min |
🤖 K8s 集群批量配置
Shell 脚本版
bash
#!/bin/bash
MIRROR_URL="你的加速源地址"
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak.$(date +%Y%m%d)
containerd config default > /etc/containerd/config.toml
cat >> /etc/containerd/config.toml << 'EOF'
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://MIRROR_PLACEHOLDER"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://MIRROR_PLACEHOLDER/k8s"]
EOF
sed -i "s|MIRROR_PLACEHOLDER|${MIRROR_URL}|g" /etc/containerd/config.toml
systemctl daemon-reload && systemctl restart containerd
ctr -n k8s.io images pull docker.io/library/alpine:latest
Ansible 批量下发版
yaml
- name: 配置 K8s containerd 镜像加速
hosts: k8s_nodes
become: yes
tasks:
- name: 注入 mirrors 配置并重启
shell: |
containerd config default > /etc/containerd/config.toml
cat >> /etc/containerd/config.toml << 'CONF'
[plugins."io.containerd.grpc.v1.cri".registry.mirrors]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://{{ mirror_url }}"]
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."registry.k8s.io"]
endpoint = ["https://{{ mirror_url }}/k8s"]
CONF
systemctl daemon-reload && systemctl restart containerd
- name: 验证
command: ctr -n k8s.io images pull docker.io/library/alpine:latest
⚡ 踩坑速查
改了配置不生效? → 检查 systemctl show containerd | grep ExecStart 确认配置文件路径
ctr pull 成功但 K8s 还是报错? → 你用了默认命名空间,要加 -n k8s.io
TLS 证书报错? → 在 configs 里加 insecure_skip_verify = true(生产环境慎用)
kubeadm init 卡住? → init 之前先配好加速,手动 kubeadm config images pull --image-repository=加速源/k8s
总结
| 场景 | 推荐 | 理由 |
|---|---|---|
| 个人学习 / 小集群 | 国内加速服务 | 开箱即用 |
| 企业生产集群 | 自建 Registry | 可控性强 |
| CI/CD | nerdctl 预拉取 | 灵活集成 |
| 临时救急 | 国内加速服务 | 5 分钟搞定 |
别等到凌晨被叫醒才开始搞这个。有问题评论区见 👇
2026 年 4 月实测,方案时效性请自行验证。