背景
今天,我的 Kubernetes 集群中的一个 Pod 重启并切换到了另一个节点。由于是部署的kubesphere,没关注代理的事情,然而,由于国内网络环境无法直接访问 Docker 官方服务器,新节点没有镜像,导致新节点无法拉取所需的镜像 ,最终 Pod 启动失败。由于事情紧急,决定在有镜像的服务器上备份一个出来同步到其他节点,经过一番折腾,我找到了解决方案,并在此分享给大家。
问题分析
- Pod 重启并切换节点:Kubernetes 的调度器将 Pod 调度到了一个没有所需镜像的节点。
- 镜像拉取失败:由于国内网络限制,节点无法从 Docker 官方服务器拉取镜像。
- 解决方案:将已有节点上的镜像同步到新节点,避免直接拉取。
解决方案
前提条件
- 集群中至少有一个节点已经存在所需的镜像。
- 使用
containerd
作为容器运行时(K3s 默认使用containerd
)。
步骤 1:在已有镜像的节点上导出镜像
使用 ctr
(containerd
的命令行工具)将镜像导出为 tar 文件:
bash
ctr -n k8s.io images export ks-controller-manager.tar docker.io/kubesphere/ks-controller-manager:latest
注意:
-n k8s.io
指定命名空间为k8s.io
,这是 K3s 使用的containerd
命名空间。docker.io/kubesphere/ks-controller-manager:latest
是镜像的名称和标签,请根据实际情况替换。
步骤 2:将 tar 文件传输到目标节点
使用 scp
或其他工具将 tar 文件传输到目标节点:
scss
scp ks-controller-manager.tar user@xx.xx.xx.xx:/opt
步骤 3:在目标节点上导入镜像
在目标节点上,使用 ctr
导入镜像:
arduino
ctr -n k8s.io images import /opt/ks-controller-manager.tar
步骤 4:验证镜像是否导入成功
检查镜像是否已成功导入:
bash
ctr -n k8s.io images list | grep kubesphere/ks-controller-manager
步骤 5:重启相关 Pod
如果 Kubernetes 中有 Pod 依赖该镜像,可能需要重启这些 Pod:
ini
kubectl delete pod -n kubesphere-system -l app=ks-controller-manager
Kubernetes 会自动重新创建这些 Pod,并使用新导入的镜像。
步骤 6:检查 Pod 状态
确保 Pod 正常运行:
ini
kubectl get pods -n kubesphere-system -l app=ks-controller-manager
额外提示
如果 ctr
不可用,可以尝试使用 crictl
(Kubernetes 的 CRI 工具)来操作镜像:
-
导出镜像:
bashcrictl pull docker.io/kubesphere/ks-controller-manager:latest crictl images --digests | grep kubesphere/ks-controller-manager
-
在目标节点上拉取镜像:
bashcrictl pull docker.io/kubesphere/ks-controller-manager:latest
-
验证镜像:
bashcrictl images | grep kubesphere/ks-controller-manager
总结
通过以上步骤,我们可以将已有节点上的镜像同步到新节点,从而避免因国内网络限制导致的镜像拉取失败问题。这种方法不仅适用于 K3s,也适用于其他使用 containerd
作为容器运行时的 Kubernetes 集群。