K8s 1.28 安装 Flannel 卡在 ImagePullBackOff?别慌,手把手教你用 ctr 命令手动拉取镜像搞定
当你满怀期待地在 Kubernetes 1.28 集群上部署 Flannel 网络插件时,突然发现 Pod 状态卡在ImagePullBackOff,那种感觉就像开车时突然遇到路障。别担心,这不是世界末日,而是一个可以通过 containerd 的ctr命令轻松解决的常见问题。
1. 理解问题根源:为什么会出现 ImagePullBackOff
在开始解决问题之前,我们需要先理解这个错误的本质。ImagePullBackOff是 Kubernetes 报告的一种 Pod 状态,表示 kubelet 无法从指定的镜像仓库拉取容器镜像。这通常由以下几种情况导致:
- 网络连接问题:无法访问 Docker Hub 或其他镜像仓库
- 认证问题:需要认证的私有仓库但未配置正确的凭据
- 镜像不存在:指定的镜像标签或版本不存在
- 资源限制:节点磁盘空间不足或内存限制
在 Flannel 安装场景中,最常见的原因是网络连接问题,特别是当你的集群位于内网环境或对国外镜像仓库(如 docker.io)的访问受限时。
# 查看 Pod 详细状态 kubectl describe pod -n kube-system kube-flannel-ds-xxxxx在输出中,你可能会看到类似这样的错误信息:
Failed to pull image "docker.io/flannel/flannel:v0.22.3": rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/flannel/flannel:v0.22.3": failed to resolve reference "docker.io/flannel/flannel:v0.22.3": failed to do request: Head "https://registry-1.docker.io/v2/flannel/flannel/manifests/v0.22.3": dial tcp: lookup registry-1.docker.io on 10.96.0.10:53: read udp 10.244.0.3:43214->10.96.0.10:53: i/o timeout2. 为什么选择 ctr 命令而非传统解决方案
面对镜像拉取问题,常见的解决方案包括:
- 配置镜像加速器或代理
- 修改 Docker/containerd 配置使用国内镜像源
- 手动下载镜像并导入
然而,这些方法各有局限:
| 方法 | 优点 | 缺点 |
|---|---|---|
| 镜像加速器 | 长期有效 | 需要修改集群配置,可能影响其他服务 |
| 国内镜像源 | 下载速度快 | 镜像可能不完整或版本滞后 |
| 手动导入 | 直接解决问题 | 传统方法操作复杂 |
ctr命令是 containerd 自带的客户端工具,相比传统方法有独特优势:
- 无需修改集群配置:直接在节点上操作,不影响其他服务
- 精确控制镜像命名空间:通过
-n k8s.io参数确保镜像能被 kubelet 识别 - 即时生效:拉取后 Kubernetes 能立即使用,无需额外步骤
3. 实战:使用 ctr 命令手动拉取 Flannel 镜像
3.1 准备工作
首先,确认你的环境:
- Kubernetes 1.28 集群
- 使用 containerd 作为容器运行时(默认配置)
- 拥有节点上的 sudo 权限
# 检查容器运行时 kubectl get node -o wide3.2 确定需要的镜像版本
查看 Flannel 的部署清单文件,找到需要的镜像:
# 下载最新版 Flannel 部署文件 curl -LO https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml # 查看需要的镜像 grep image kube-flannel.yml通常会输出两个镜像:
image: docker.io/flannel/flannel-cni-plugin:v1.2.0 image: docker.io/flannel/flannel:v0.22.33.3 使用 ctr 命令拉取镜像
关键步骤来了,使用ctr命令拉取镜像,特别注意-n k8s.io参数:
# 拉取 flannel-cni-plugin 镜像 sudo ctr -n k8s.io images pull docker.io/flannel/flannel-cni-plugin:v1.2.0 # 拉取 flannel 主镜像 sudo ctr -n k8s.io images pull docker.io/flannel/flannel:v0.22.3注意:
-n k8s.io参数至关重要,它指定了镜像的命名空间,确保 kubelet 能够识别这些镜像。如果省略这个参数,镜像会被拉到默认命名空间,Kubernetes 将无法使用。
3.4 验证镜像拉取成功
检查镜像是否已正确拉取:
sudo ctr -n k8s.io images list | grep flannel应该能看到类似输出:
docker.io/flannel/flannel-cni-plugin:v1.2.0 docker.io/flannel/flannel:v0.22.34. 高级技巧与疑难解答
4.1 使用镜像加速器
如果直接拉取仍然太慢,可以尝试使用镜像加速器:
# 使用阿里云镜像加速 sudo ctr -n k8s.io images pull registry.aliyuncs.com/google_containers/flannel:v0.22.3然后重新打标签:
sudo ctr -n k8s.io images tag registry.aliyuncs.com/google_containers/flannel:v0.22.3 docker.io/flannel/flannel:v0.22.34.2 多架构镜像支持
如果你的集群混合了不同架构的节点(如 amd64 和 arm64),需要拉取多架构镜像:
sudo ctr -n k8s.io images pull --platform linux/amd64,linux/arm64 docker.io/flannel/flannel:v0.22.34.3 常见错误处理
错误1:权限不足
ctr: permission denied解决方案:确保使用 sudo 执行命令
错误2:镜像拉取后 Pod 仍无法启动
可能原因:镜像被拉取到了错误的命名空间
解决方案:确认使用了-n k8s.io参数,并检查镜像列表
sudo ctr -n k8s.io images list | grep flannel5. 为什么这个方法有效:深入理解 containerd 和 kubelet 的交互
理解背后的原理能帮助你在类似场景中举一反三。Kubernetes 通过 kubelet 管理节点上的容器,而 kubelet 通过 CRI(Container Runtime Interface)与容器运行时(如 containerd)通信。
当使用ctr -n k8s.io命令时,我们直接将镜像放入了 kubelet 管理的命名空间,因此:
- kubelet 能立即发现这些镜像
- 不需要额外的镜像缓存同步过程
- 避免了权限和命名空间隔离导致的问题
相比之下,使用docker pull或ctr不加-n k8s.io时,镜像会被放在默认命名空间,kubelet 无法直接访问,需要额外的导入导出操作。
6. 其他替代方案对比
虽然ctr命令是最直接的解决方案,但了解其他方法也有价值:
方法一:配置 containerd 镜像加速器
编辑/etc/containerd/config.toml:
[plugins."io.containerd.grpc.v1.cri".registry.mirrors] [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"] endpoint = ["https://registry-1.docker.io", "https://mirror.gcr.io"]然后重启 containerd:
sudo systemctl restart containerd方法二:使用国内镜像源
修改 Flannel 的部署文件,将docker.io/flannel/flannel:v0.22.3替换为国内镜像源地址。
方法三:手动导入导出镜像
在有网络的环境中拉取镜像,导出为 tar 文件,再导入到目标集群:
# 在有网络的机器上 docker pull flannel/flannel:v0.22.3 docker save flannel/flannel:v0.22.3 > flannel.tar # 在目标集群上 sudo ctr -n k8s.io images import flannel.tar7. 预防措施与最佳实践
为了避免未来遇到类似问题,可以考虑以下预防措施:
- 预先拉取镜像:在集群初始化前拉取所有需要的镜像
- 搭建本地镜像仓库:在内网部署 Harbor 或其他 registry
- 使用镜像缓存:配置 containerd 的镜像缓存策略
- 监控镜像拉取状态:设置告警及时发现镜像拉取失败
对于生产环境,我通常会预先在部署脚本中加入镜像拉取步骤:
# 预拉取关键镜像 PRELOAD_IMAGES=( "flannel/flannel:v0.22.3" "flannel/flannel-cni-plugin:v1.2.0" "k8s.gcr.io/pause:3.6" ) for image in "${PRELOAD_IMAGES[@]}"; do sudo ctr -n k8s.io images pull "docker.io/${image}" || \ sudo ctr -n k8s.io images pull "registry.aliyuncs.com/google_containers/${image##*/}" done在实际工作中,遇到ImagePullBackOff这类问题时,最重要的是保持冷静,逐步排查。ctr命令虽然强大,但只是众多工具中的一种。理解容器运行时的工作原理,才能在各种网络环境下游刃有余地部署 Kubernetes 集群。