K8s 中 /etc/resolv.conf 断链引发 connect: connection refused 错误排查记录

文章目录

  • 问题现场
  • 查因过程
  • 根因
  • 解决方案
    • [方法一:恢复 /etc/resolv.conf 到标准格式](#方法一:恢复 /etc/resolv.conf 到标准格式)
    • [方法二:重新启用 systemd-resolved(如需要)](#方法二:重新启用 systemd-resolved(如需要))
  • 验证
  • 总结

在一次 Kubernetes 单节点集群部署中,我遇到一个令人困惑的问题:Pod 启动失败、Kubernetes 控制面组件无法解析 DNS、etcd 报错......最终发现元凶竟然是 /etc/resolv.conf 的"断链"!

本文将记录问题发生的背景、分析过程和最终解决方案,并解释为什么这种事在"什么都没动"的情况下仍然会发生。

问题现场

在我的hyperv环境更换vswitch后,做kubectl get操作

bash 复制代码
kubectl get nodes

报出如下错误:

bash 复制代码
E0521 15:16:21.293830    2123 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: Get \"https://k8sm01.lab.com:6443/api?timeout=32s\": dial tcp 172.20.32.247:6443: connect: connection refused"

解读如下:

    1. E0521
      E 代表 Error,表示这是一个错误级别的日志。
      0521 表示发生的日期是 5 月 21 日(即 05 月 21 日)。
    1. 15:16:21.293830
      表示错误发生的 时间,精确到微秒:
      15 点 16 分 21 秒 293830 微秒。
    1. 2123
      这是日志产生的 进程 ID (PID),即哪个程序进程产生了这条日志。
    1. memcache.go:265
      表示出错的文件和行数:
      在源码文件 memcache.go 的 第 265 行。
    1. "Unhandled Error"
      这是一个通用错误标签,表示这个错误没有被特别处理(即程序没有处理它,只是记录下来)。
    1. err="couldn't get current server API group list: ..."
      这是错误的具体内容:
bash 复制代码
Get \"https://k8sm01.lab.com:6443/api?timeout=32s\": 
dial tcp 172.20.32.247:6443: connect: connection refused"

说明客户端(kubectl 或 kubelet)尝试访问 API Server 时,目标 IP 172.20.32.247 上的端口 6443 无响应,连接被拒绝。

查因过程

查看kubelet状态

bash 复制代码
systemctl status kubelet.service

输出:

bash 复制代码
 systemctl status kubelet.service
● kubelet.service - kubelet: The Kubernetes Node Agent
     Loaded: loaded (/usr/lib/systemd/system/kubelet.service; enabled; preset: enabled)
    Drop-In: /usr/lib/systemd/system/kubelet.service.d
             └─10-kubeadm.conf
     Active: active (running) since Wed 2025-05-21 15:07:30 UTC; 39min ago
       Docs: https://kubernetes.io/docs/
   Main PID: 2046 (kubelet)
      Tasks: 10 (limit: 2194)
     Memory: 26.0M (peak: 27.9M)
        CPU: 1min 16.014s
     CGroup: /system.slice/kubelet.service
             └─2046 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/>

May 21 15:47:02 k8sm01.lab.com kubelet[2046]: E0521 15:47:02.112556    2046 pod_workers.go:1301] "Error syncing pod, skipping" err="failed to \"CreatePodSandbox\" for >
May 21 15:47:02 k8sm01.lab.com kubelet[2046]: E0521 15:47:02.113034    2046 dns.go:284] "Could not open resolv conf file." err="open /run/systemd/resolve/resolv.conf: >
May 21 15:47:02 k8sm01.lab.com kubelet[2046]: E0521 15:47:02.113069    2046 kuberuntime_sandbox.go:45] "Failed to generate sandbox config for pod" err="open /run/syste>
May 21 15:47:02 k8sm01.lab.com kubelet[2046]: E0521 15:47:02.113090    2046 kuberuntime_manager.go:1170] "CreatePodSandbox for pod failed" err="open /run/systemd/resol>
May 21 15:47:02 k8sm01.lab.com kubelet[2046]: E0521 15:47:02.113137    2046 pod_workers.go:1301] "Error syncing pod, skipping" err="failed to \"CreatePodSandbox\" for 

由于systemctl输出的日志被截断,使用journalctl获取完整日志:

bash 复制代码
 journalctl -b 0 --since=today -u kubelet --no-pager

输出:

bash 复制代码
......
May 21 15:51:50 k8sm01.lab.com kubelet[2046]: E0521 15:51:50.122721    2046 dns.go:284] "Could not open resolv conf file." err="open /run/systemd/resolve/resolv.conf: no such file or directory"
May 21 15:51:50 k8sm01.lab.com kubelet[2046]: E0521 15:51:50.122778    2046 kuberuntime_sandbox.go:45] "Failed to generate sandbox config for pod" err="open /run/systemd/resolve/resolv.conf: no such file or directory" pod="kube-system/kube-scheduler-k8sm01.lab.com"
May 21 15:51:50 k8sm01.lab.com kubelet[2046]: E0521 15:51:50.122814    2046 kuberuntime_manager.go:1170] "CreatePodSandbox for pod failed" err="open /run/systemd/resolve/resolv.conf: no such file or directory" pod="kube-system/kube-scheduler-k8sm01.lab.com"
May 21 15:51:50 k8sm01.lab.com kubelet[2046]: E0521 15:51:50.122879    2046 pod_workers.go:1301] "Error syncing pod, skipping" err="failed to \"CreatePodSandbox\" for \"kube-scheduler-k8sm01.lab.com_kube-system(0b6d714931c0469558b131ba4fad4975)\" with CreatePodSandboxError: \"Failed to generate sandbox config for pod \\\"kube-scheduler-k8sm01.lab.com_kube-system(0b6d714931c0469558b131ba4fad4975)\\\": open /run/systemd/resolve/resolv.conf: no such file or directory\"" pod="kube-system/kube-scheduler-k8sm01.lab.com" podUID="0b6d714931c0469558b131ba4fad4975"
May 21 15:51:50 k8sm01.lab.com kubelet[2046]: E0521 15:51:50.369772    2046 controller.go:145] "Failed to ensure lease exists, will retry" err="Get \"https://k8sm01.lab.com:6443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/k8sm01.lab.com?timeout=10s\": dial tcp 172.20.32.247:6443: connect: connection refused" interval="7s"
.......

kubelet 日志已经揭示了关键问题:Kubelet 在尝试创建 Pod 的 Sandbox 时失败了,而根本原因是它无法读取 DNS 配置文件 /run/systemd/resolve/resolv.conf

根因

在使用 systemd-resolved 的 Linux 系统中(如 Ubuntu 18+),/etc/resolv.conf 默认是个符号链接,指向:

bash 复制代码
ls -alh /etc/resolv.conf
lrwxrwxrwx 1 root root 39 Apr 23  2024 /etc/resolv.conf -> ../run/systemd/resolve/stub-resolv.conf

由于某些原因, /etc/resolv.conf 仍指向那个已不存在的文件,就会造成容器(例如 etcd、kubelet、CoreDNS)无法解析 DNS。

解决方案

方法一:恢复 /etc/resolv.conf 到标准格式

检查当前链接:

bash 复制代码
ls -l /etc/resolv.conf

如果输出类似:

bash 复制代码
/etc/resolv.conf -> /run/systemd/resolve/resolv.conf

但 /run/systemd/resolve/resolv.conf 不存在,那么可以临时替换为传统 resolv.conf:

bash 复制代码
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

重新启动 kubelet:

bash 复制代码
sudo systemctl restart kubelet

方法二:重新启用 systemd-resolved(如需要)

如果你之前禁用了 systemd-resolved,可以启用它:

bash 复制代码
sudo systemctl enable systemd-resolved --now

然后检查:

bash 复制代码
ls -l /etc/resolv.conf
# 如果还没有指向 /run/systemd/resolve/resolv.conf
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf

验证

确保 /etc/resolv.conf 文件有效:

bash 复制代码
cat /etc/resolv.conf

应该能看到:

bash 复制代码
nameserver 8.8.8.8

然后再检查做kubectl get操作恢复正常。

bash 复制代码
kubectl get nodes
NAME             STATUS     ROLES           AGE   VERSION
k8sm01.lab.com   Ready      control-plane   17d   v1.31.8
k8sw01.lab.com   NotReady   <none>          17d   v1.31.8

总结

这个错误的根本原因是:/etc/resolv.conf 指向了一个不存在的文件,导致 Kubernetes 组件无法进行 DNS 解析。

最直接修复方法 是用 echo "nameserver 8.8.8.8" > /etc/resolv.conf 方式写入一个有效 DNS 配置,然后重启 kubelet。

相关推荐
轮到我狗叫了10 分钟前
智慧在线判题OJ系统项目总体,包含功能开发思路,内部中间件,已经部分知识点
微服务·云原生·架构
莱茵不哈哈1 小时前
Docker:容器化技术
运维·docker·容器
morliz子轩3 小时前
部署Gitlab-CE with Docker私有云环境
docker·容器·gitlab
Java 技术轻分享3 小时前
初识 RocketMQ 知识总结:基础概念、架构解析、核心特性与应用场景
云原生·中间件·架构·消息队列·rocketmq
吾日三省吾码3 小时前
ZooKeeper 原理解析及优劣比较
分布式·zookeeper·云原生
Dust | 棉花糖5 小时前
云原生+大数据
java·大数据·云原生
富士康质检员张全蛋9 小时前
Kubernetes etcd 故障恢复(1)
容器·kubernetes·etcd
Spring_java_gg9 小时前
Kubernetes 运维操作手册:从 etcd 快照进行精确恢复
运维·云原生·容器·kubernetes·etcd
项目題供诗15 小时前
黑马k8s(十二)
云原生·容器·kubernetes