1. 问题现象
在部署 Kubernetes v1.24+ 版本(如 v1.35)并使用 Docker 作为运行时环境时,重启 Master 节点后,执行 kubectl get nodes 出现连接被拒绝的报错:
1 | E0123 06:25:39.253691 5936 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://master:6443/api?timeout=32s\": dial tcp 192.168.109.100:6443: connect: connection refused" |
进一步排查 kubelet 服务日志 (journalctl -xefu kubelet),发现关键报错:
Error while dialing: dial unix /var/run/cri-dockerd.sock: connect: no such file or directory
检查 cri-dockerd 服务状态时,发现服务未启动。但其实我是配置了cri-dockerd服务开机自动启动的,所以这里的主要问题是为什么自动启动失败。
进一步查看报错,提示 Socket 无法加载主服务:
1 | systemd[1]: cri-docker.socket: Socket service cri-docker.service not loaded, refusing. |
2. 原因分析
- API Server 无法连接的原因:Kubernetes v1.24+ 移除了 Dockershim,使用 Docker 必须通过
cri-dockerd中间件。如果cri-dockerd未运行,Kubelet 就无法驱动 Docker,导致 API Server 容器无法启动。 cri-dockerd服务启动失败的原因:cri-dockerd通常配置为 Socket Activation 模式。这意味着cri-dockerd.socket负责创建/var/run/cri-dockerd.sock文件并监听请求,收到请求后才拉起cri-dockerd.service。如果 Socket 没启动,Kubelet 就找不到 sock 文件。- Socket未启动的原因:
- 命名不一致:Socket 文件配置了
PartOf=cri-dockerd.service,但文件系统中只有cri-docker.service(少了个 d),导致 Systemd 找不到依赖服务。 - 语法错误:Systemd Unit 文件中不支持行内注释(如
Requires=xxx # 注释),这会导致整行解析失败,依赖关系失效。
- 命名不一致:Socket 文件配置了
3. 解决方案
1. 先停止并禁用可能存在的旧服务,避免冲突
1 | systemctl stop cri-docker.socket cri-docker.service |
2.规范化服务名称与配置
为了避免混淆,建议统一将 Service 和 Socket 文件命名为 cri-dockerd(带 d)。
修复 Service 文件 (/etc/systemd/system/cri-dockerd.service):
注意:去掉所有行内注释,确保无多余换行。
1 | [Unit] |
修复 Socket 文件 (/etc/systemd/system/cri-dockerd.socket):
注意:PartOf 必须严格匹配 Service 的文件名。
1 | [Unit] |
3. 重新加载并启动
如果之前存在不一致的文件(如 cri-docker.service),需要清理掉,避免 Systemd 冲突。
1 | # 重新加载配置 |
4. 验证状态
1 | systemctl status cri-dockerd.socket |
如果这个是 Active (running),那么 /var/run/cri-dockerd.sock 就会存在,kubelet也就能正常连接了。
5. 最后重启Kubelet
1 | systemctl restart kubelet |