侧边栏壁纸
博主头像
汪洋

即使慢,驰而不息,纵会落后,纵会失败,但一定可以达到他所向的目标。 - 鲁迅

  • 累计撰写 224 篇文章
  • 累计创建 85 个标签
  • 累计收到 273 条评论

故障排查 - 一次延迟爆发的故障:K8s节点扩容后,DNS 解析全面超时!

汪洋
2025-11-10 / 0 评论 / 0 点赞 / 7 阅读 / 3,037 字

一、事故背景

某天上午,集群监控突然开始告警:多个服务间调用延迟飙升、部分请求直接超时。起初我们以为是偶发的网络抖动(没有版本变更),但随着告警范围扩大、业务量上升,问题开始呈现“指数级爆发”。

翻查日志后,几条关键的错误信息引起注意:

plugin/errors aps-service.paas.svc.cluster.local,localdomain, A: unreachable backend: no upstream host
aps-service.paas.svc.cluster.local.localdomain. A: unreachable backend: read udp 172.21.33.4:44195->8.8.4.4:53: i/o timeout

看似只是 DNS 超时,然而在 Kubernetes 集群中,这种异常往往牵扯的不止一层。

二、故障回溯

经过排查,最终我们发现所有出问题的 Pod 都部署在新扩容的 K8s 节点上。

实际上,这个节点在扩容当天就已经有部分服务实例运行在上面,但由于集群中同类实例较多,系统整体仍能正常工作,冒烟测试也顺利通过,因此问题并未立即显现。

直到第二天业务高峰期,随着流量上升、调度器在该节点上分配了更多 Pod,DNS 异常才被集中放大,导致调用超时、告警频发,故障由此全面爆发。

三、初步分析

错误信息揭示了几个关键点:

  • aps-service.paas.svc.cluster.local → 目标是集群内部服务
  • unreachable backend → CoreDNS 无法找到可用后端
  • no upstream host → 没有健康的上游可响应
  • read udp -> 8.8.4.4:53 timeout → CoreDNS 查询外部 DNS 时超时

问题范围限定在新节点,且与 DNS 强相关。下一步,进入问题节点的 Pod 内查看 DNS 配置。

四、现场取证

在故障 Pod 内执行:

cat /etc/resolv.conf

输出如下:

search default.svc.cluster.local svc.cluster.local cluster.local local-domain
nameserver 10.245.0.10
options ndots:5

发现问题关键点:多出了一个 localdomain 搜索域。这意味着,当应用尝试解析 aps-service.paas.svc.cluster.local 时,系统会依次尝试:

  1. aps-service.paas.svc.cluster.local.default.svc.cluster.local
  2. aps-service.paas.svc.cluster.local.svc.cluster.local
  3. aps-service.paas.svc.cluster.local.cluster.local
  4. aps-service.paas.svc.cluster.local.localdomain ← ❌ 错误附加
  5. aps-service.paas.svc.cluster.local

最后一步解析 .localdomain 时超时,从而导致整个请求链路阻塞。

五、深挖根因

Pod 的 DNS 配置来源于 kubelet 的 --resolv-conf 参数,我们检查了新节点的配置:

cat /var/lib/kubelet/config.yaml | grep resolvConf
resolvConf: "/etc/resolv.conf"

再查看宿主机的 /etc/resolv.conf:

# Generated by NetworkManager
search localdomain
nameserver 10.228.5.240

真相浮现—— NetworkManager 自动生成的 resolv.conf 添加了 “localdomain” 搜索域, 而 kubelet 恰好继承了这份配置,污染到了所有在此节点运行的 Pod。
也就是说,问题根源是扩容节点的 DNS 被 NetworkManager 污染!

六、修复过程

步骤一:清理 NetworkManager 干扰

在服务器(K8s 节点)上,NetworkManager 主要用于桌面系统的网络自动化管理,而在生产环境中,它往往会与手动配置的网络或容器网络插件(如 CNI)产生冲突。最典型的问题就是:它会自动重写 /etc/resolv.conf,加入类似 search localdomain 的字段,进而污染 Pod 的 DNS 配置。推荐做法(稳定优先): 直接关闭 NetworkManager 服务,彻底避免其干扰。

systemctl stop NetworkManager
systemctl disable NetworkManager

同时,删除 /etc/resolv.conf 文件中的这一行:

search localdomain

这样可确保节点的 DNS 配置保持稳定,不再被系统进程自动修改。

如果出于运维统一或其他原因,不便关闭 NetworkManager: 可以通过修改其配置文件来禁用 DNS 管理功能:编辑 /etc/NetworkManager/NetworkManager.conf:

[main]
dns=none

保存后执行:

systemctl restart NetworkManager

此配置将阻止 NetworkManager 再次覆盖 /etc/resolv.conf,在保持服务运行的同时也能避免污染集群 DNS。

步骤二:修正 kubelet 配置

编辑配置文件:

vim /var/lib/kubelet/config.yaml

将:

resolvConf: "/etc/resolv.conf"

改为:

resolvConf: "/run/kubelet/resolv.conf"

新文件内容保持最简洁:

nameserver 10.245.0.10
search svc.cluster.local cluster.local
options ndots:5

保存后重启 kubelet:

systemctl restart kubelet

步骤三:验证结果

在修复节点后,重新调度 Pod 并验证:

kubectl exec -it-- nslookup aps-service.paas.svc.cluster.local

返回结果正常:

Name: aps-service.paas.svc.cluster.local
Address: 10.254.12.8

DNS 解析恢复,服务调用延迟恢复正常。

七、经验复盘

根因链条完整复盘:

节点扩容 → NetworkManager 自动生成 localdomain → kubelet 继承 /etc/resolv.conf →
Pod DNS 被污染 → CoreDNS 查询错误 → 大规模 DNS 超时

经验总结:

  1. Kubernetes 节点不应依赖 NetworkManager
  • 关闭该服务或在系统初始化时禁用。
  • 注意不要误配置
  1. 统一 kubelet 的 resolv.conf 配置
  • 推荐使用 /run/kubelet/resolv.conf 或专门维护的模板文件。
  1. DNS 配置应保持最小可控
  • 避免多余 search 域和外部 nameserver 污染。
  1. 扩容节点上线前要做健康校验
  • 包括 kubelet 配置、网络路由、DNS 可达性等。

八、结语

这次看似简单的 DNS 故障,其实隐藏了扩容节点配置不一致的问题。 更值得警醒的是:问题并未立即暴露,而是在第二天业务高峰时集中爆发。在复杂的云原生体系中,稳定性从来不靠“侥幸”,而是靠每一个小细节的规范与一致。

0

评论区