返回首页

K8s DNS 间歇性解析超时 5s 排查:conntrack 竞态与 ndots 放大

📅 创建于 2026-06-15 🔄 更新于 2026-06-15 📝 447 字

来源:AI炼丹踩坑 | 发布日期:2026-06-11

K8s DNS 间歇性解析超时 5s 排查

一句话复盘: Pod 访问外部域名偶发 dial tcp: lookup api.example.com: i/o timeout,超时稳定卡在 5s(glibc resolver 默认 timeout)。根因并非 CoreDNS 繁忙,而是 DNS UDP 请求经过 kube-proxy iptables 转发时,conntrack 发生竞态丢包,加上 ndots:5 放大了请求量。组合方案:NodeLocal DNSCache + ndots 调优。


问题现象

线上接口 P99 突然多了一个 5 秒 的尖刺,随机慢、重试即好。应用日志:

dial tcp: lookup api.example.com: i/o timeout

排查链路

第一步:确认是 5s 超时(glibc 特征)

DNS 超时的 5 秒不是玄学 — glibc resolver 默认 timeout 就是 5 秒。Pod 内压测验证:

while true; do date; time getent hosts api.example.com; sleep 0.2; done

输出典型:

real    0m5.012s

稳定在 5s 附近 → 沿 Linux DNS resolver 链路排查。

第二步:检查 CoreDNS 是否真的繁忙

kubectl -n kube-system top pod -l k8s-app=kube-dns
kubectl -n kube-system describe pod coredns-xxx

CoreDNS CPU 很低,无 throttling,日志无错误。DNS 超时 ≠ CoreDNS 慢 — 请求可能丢在内核路径上,根本没到 CoreDNS。

第三步:节点抓包确认丢包

找到异常 Pod 所在节点,抓 DNS 流量:

tcpdump -i any -nn udp port 53

异常时现象(中间沉默约 5 秒):

10.244.1.23.45121 > 10.96.0.10.53: A? api.example.com
10.244.1.23.45121 > 10.96.0.10.53: AAAA? api.example.com
# ~5s 沉默
10.244.1.23.45122 > 10.96.0.10.53: A? api.example.com

第一次请求无响应,5s 后换源端口重试即成功 → 指向 conntrack 竞态。

第四步:看 conntrack 统计

conntrack -S | egrep 'insert_failed|drop|invalid'
dmesg | grep nf_conntrack

insert_failed 持续增长且与 DNS 超时峰值对齐,即可确认方向。注意区分:表满(table full, dropping packet)与竞态(insert_failed 增长但未满)是两种不同问题。


根因链

ndots:5 放大 DNS 请求量
        ↓
glibc 同时发起 A + AAAA 查询,同源端口竞争 conntrack entry
        ↓
conntrack 竞态 → 失败包被内核丢弃
        ↓
glibc 等待 5s 超时后重试(换源端口成功)

ndots:5 是帮凶。 K8s 默认 ndots:5 会让含少于 5 个点的域名先拼上 search domain 逐条尝试(如 api.example.com.default.svc.cluster.local),外部域名越多,conntrack 压力越大。


解决方案对比

方案 效果 成本 适用场景
NodeLocal DNSCache 中大规模集群、DNS QPS 高
调低 ndots 中-高 外部域名访问多的服务
外部域名加尾点 配置可控的业务
DNS over TCP 少量核心服务止血
调大 conntrack conntrack 表满
升级内核 节点体系可控

推荐组合(实战验证):

  1. 核心业务配置 ndots:2
  2. 高频外部域名加尾点(api.example.com.
  3. 集群灰度上线 NodeLocal DNSCache
  4. 同步监控 conntrack 指标 + CoreDNS QPS

排查 Checklist

遇到类似问题按此顺序:

  1. time getent hosts <domain> — 确认是否 5s
  2. 📋 cat /etc/resolv.conf — 看 nameserver / search / ndots
  3. 📊 kubectl -n kube-system top pod -l k8s-app=kube-dns — CoreDNS 资源
  4. 🔍 tcpdump -i any -nn udp port 53 — 抓包看首次请求是否有响应
  5. 📈 conntrack -S | egrep 'insert_failed' — conntrack 竞态
  6. 🗄 dmesg | grep nf_conntrack — 表是否满

核心判断: CoreDNS 无压力 + 抓包首次请求无响应 + insert_failed 增长 → 别再盲目扩 CoreDNS,问题在 conntrack/UDP 链路。


关联页面

页面关联点
k8s-dns-iptables-troubleshootingiptables 封禁 53 端口引发的另一例 K8s DNS 雪崩
k8s-coredns-custom-domain-resolutionCoreDNS 自定义域名解析配置
dns-troubleshooting-practical-guide通用 DNS 全链路排查方法论
k8s-service-access-troubleshootingK8s 服务访问排障十步工作流
network-troubleshooting-order网络排障分层顺序