为何crictl可拉取本地镜像,K3s部署却失败?
问题原因与解决办法
这个问题我之前碰到过类似的,核心原因其实很好理解:
你在master节点(pikey)上用crictl pull拉取的镜像只存在于pikey本地的容器存储中,而K3s的调度器会根据集群资源情况把Pod分配到任意Ready的节点——大概率是你的worker节点(pinode-1/2/3)。这些worker节点上不仅没有这个镜像,而且当它们尝试拉取localhost:5000/pilab/node-intro-img时,localhost指向的是worker自身,不是你搭建私有仓库的master节点,自然就会出现镜像拉取失败的错误。
另外还有个可能:你的master节点防火墙没开放5000端口,导致worker节点根本连不上你的私有仓库。
具体解决方案
方案1:让集群所有节点都能访问私有仓库(推荐生产/长期测试用)
这是最规范的做法,步骤如下:
替换镜像标签为master节点的实际IP
先找到pikey的局域网IP(比如192.168.1.100,你可以用ip a命令查看),然后重新给镜像打标签并推送到私有仓库:sudo docker tag node-intro-img 192.168.1.100:5000/pilab/node-intro-img sudo docker push 192.168.1.100:5000/pilab/node-intro-img之后创建deployment时用这个带IP的镜像地址:
sudo kubectl create deployment node-intro --image=192.168.1.100:5000/pilab/node-intro-img确保worker节点能连通master的5000端口
先在pikey上开放5000端口(如果用ufw防火墙的话):sudo ufw allow 5000/tcp然后在任意一个worker节点上测试连通性:
curl http://192.168.1.100:5000/v2/如果返回
{}说明网络没问题。
方案2:手动同步镜像到所有worker节点(适合小规模集群测试)
如果你的集群只有几个节点,手动同步镜像也是个快速解决办法:
- 在pikey上导出镜像:
sudo docker save localhost:5000/pilab/node-intro-img > node-intro-img.tar - 用scp把镜像包传到每个worker节点:
scp node-intro-img.tar pi@pinode-1:~/ scp node-intro-img.tar pi@pinode-2:~/ scp node-intro-img.tar pi@pinode-3:~/ - 在每个worker节点上导入镜像:
之后再创建deployment,Pod就能正常启动了。sudo docker load < node-intro-img.tar
方案3:配置镜像拉取策略为本地优先(仅适合单节点测试)
如果你只是想在master节点上测试这个Pod,不想折腾仓库和同步,可以修改deployment的镜像拉取策略:
- 先导出deployment的yaml配置:
sudo kubectl create deployment node-intro --image=localhost:5000/pilab/node-intro-img --dry-run=client -o yaml > node-intro.yaml - 编辑这个yaml文件,给容器添加
imagePullPolicy: IfNotPresent:spec: containers: - name: node-intro image: localhost:5000/pilab/node-intro-img imagePullPolicy: IfNotPresent - 用修改后的yaml创建deployment:
注意:这个方法只能保证Pod调度到已有镜像的节点(也就是pikey)时正常启动,如果被调度到worker节点还是会失败,所以只适合临时测试。sudo kubectl apply -f node-intro.yaml
内容的提问来源于stack exchange,提问作者Andrew Bucknell




