问题背景
生产 K8s 集群(v1.28)自 8 月底节点滚动升级后,部分服务间调用开始出现间歇性超时与 5xx。监控显示 API 层延时正常,Pod 间网络连通性也无异常,但业务日志中「name resolution failed」「no such host」偶发出现。初步判断疑似 DNS 解析问题,但 CoreDNS Pod 本身健康检查与日志均无明显异常。
本次故障发生在业务高峰(09:30-11:30),平均每 15 分钟出现一次解析失败,持续约 2-3 分钟后自动恢复,属于典型的「间歇性、服务发现类」故障,对长连接与重试机制敏感的服务影响尤为明显。
故障现象
- 间歇性解析失败:业务 Pod 日志中出现
lookup xxx.svc.cluster.local: no such host或i/o timeout,频率约每 15 分钟一次,每次持续 2-3 分钟。 - CoreDNS 日志无明显异常:
corednsPod 的INFO级别日志仅偶见plugin/errors记录,ERROR级别日志为空。 - dig 测试结果不稳定:在故障窗口内,从业务 Pod 执行
dig +short xxx.svc.cluster.local @10.96.0.10有时返回空,有时返回正确 IP,成功率约 60-70%。 - 缓存污染迹象:部分节点上
nslookup结果与实际 Service Endpoint 不一致,怀疑存在缓存不一致或配置漂移。 - 无节点级网络故障:
ping、traceroute、tcpdump显示跨节点连通性正常,conntrack表项也无异常。
排查过程
步骤 1:确认故障范围与时间窗口
首先通过 Prometheus 查询 coredns_dns_request_duration_seconds 与 coredns_dns_responses_total 指标,发现故障窗口内 SERVFAIL 与 NXDOMAIN 响应比例显著上升(从常态 <0.1% 升至 3-5%),确认是 DNS 层问题而非业务层重试策略。
同时检查了节点级 /etc/resolv.conf,发现所有节点均指向 10.96.0.10(CoreDNS ClusterIP),无配置漂移。
步骤 2:检查 CoreDNS 配置与版本
执行 kubectl -n kube-system get cm coredns -o yaml 发现配置与预期一致:
|
|
但进一步检查发现,forward 插件指向 /etc/resolv.conf,而宿主机 /etc/resolv.conf 内容为:
|
|
这意味着 CoreDNS 在无法解析 cluster.local 域时,会将请求转发到公司内网 DNS(172.16.1.1),而该 DNS 服务器对 cluster.local 无感知,会返回 NXDOMAIN 或超时。
步骤 3:定位配置漂移根源
进一步检查发现,CoreDNS Deployment 的 spec.template.spec.dnsPolicy 为 Default,而非推荐的 ClusterFirst。这导致 CoreDNS Pod 自身继承宿主机的 DNS 配置,而非使用 Kubernetes 内置 DNS。
同时发现,近期节点升级时,某批次节点 /etc/resolv.conf 被云平台初始化脚本覆盖,search 与 options 参数与集群不一致,导致部分 CoreDNS Pod 在启动时读取到「污染」的上游 DNS 配置。
步骤 4:验证缓存与 TTL 不一致
通过 kubectl exec -it coredns-xxxx -- /bin/sh 进入 CoreDNS Pod,执行 dig +short xxx.svc.cluster.local @127.0.0.1 与从业务 Pod 执行的 dig 结果对比,发现:
- CoreDNS 缓存 TTL 为 30 秒(配置中
cache 30),但上游公司 DNS 返回的NXDOMAIN被缓存,导致后续请求在缓存过期前持续返回错误。 - 部分节点上
kubelet的--cluster-dns与--cluster-domain参数与实际 CoreDNS Service 不一致,存在历史遗留配置。
解决方案
-
修复 CoreDNS Deployment 配置:
-
将
dnsPolicy改为ClusterFirst,确保 CoreDNS 自身使用 Kubernetes DNS 解析。 -
在
forward插件中明确指定上游 DNS,并添加policy sequential与health_check:1 2 3 4 5forward . 172.16.1.1 172.16.1.2 { max_concurrent 1000 policy sequential health_check 5s }
-
-
清理与统一节点 DNS 配置:
- 通过 DaemonSet 在所有节点上统一
/etc/resolv.conf(使用search cluster.local+options ndots:2),并通过systemd-resolved或NetworkManager锁定配置,防止云平台初始化脚本覆盖。
- 通过 DaemonSet 在所有节点上统一
-
调整 CoreDNS 缓存策略:
- 将
cache 30改为cache 15,降低 NXDOMAIN 污染窗口。 - 启用
cache prefetch机制,提前预热热点域名缓存。
- 将
-
增加健康检查与告警:
- 在 Prometheus 中增加
coredns_dns_responses_total{rcode="NXDOMAIN"}与SERVFAIL的告警规则,阈值设为 >1% 触发。 - 部署
dnsutilsPod 作为「金丝雀」,每分钟执行一次dig测试并上报结果。
- 在 Prometheus 中增加
-
回滚与验证:
- 先在 3 个节点的小范围灰度集群上验证修复效果,确认解析成功率恢复至 99.9% 以上后,全量滚动更新 CoreDNS Deployment。
根因分析
根本原因在于 CoreDNS dnsPolicy 配置为 Default 导致继承宿主机 DNS 配置,叠加节点升级时 /etc/resolv.conf 被云平台脚本覆盖,引入了公司内网 DNS(对 cluster.local 无感知)作为上游。CoreDNS 在无法解析 cluster.local 域时转发至该上游,收到 NXDOMAIN 后缓存 30 秒,导致后续请求在缓存窗口内持续失败。
次要原因包括:
forward插件缺少health_check与policy配置,无法快速剔除故障上游。- 节点 DNS 配置缺乏统一管理与锁定机制,存在配置漂移风险。
预防措施
- 配置即代码:将 CoreDNS 配置纳入 GitOps 仓库,通过 CI 校验
dnsPolicy必须为ClusterFirst,forward必须显式指定上游并启用健康检查。 - 节点 DNS 基线化:使用 DaemonSet +
systemd-resolved统一管理所有节点/etc/resolv.conf,并通过immutable属性或chattr +i锁定关键配置。 - 监控全链路:在
kube-dns、coredns、node-dns各层增加NXDOMAIN、SERVFAIL、timeout指标告警,并部署「金丝雀」测试 Pod 实时验证解析可用性。 - 变更门禁:节点系统升级、云平台初始化脚本变更前,必须执行 DNS 解析回归测试(覆盖
cluster.local与公司内网域名),并纳入变更结单证据包。 - 定期演练:每季度执行一次「DNS 配置漂移」应急演练,模拟上游 DNS 故障与缓存污染场景,验证回滚与修复流程。
总结
本次故障是典型的「配置漂移 + 缓存污染」复合场景:CoreDNS 因 dnsPolicy 配置不当继承了宿主机 DNS,节点升级时 /etc/resolv.conf 被覆盖引入公司内网 DNS,导致 cluster.local 解析间歇性失败。排查过程通过指标分析、配置比对、缓存验证三步定位根因,修复方案聚焦配置收口、缓存策略优化与监控告警三层面。
DNS 是 K8s 集群的「神经系统」,任何配置漂移都可能引发连锁反应。未来需将 DNS 配置纳入基线管理与变更门禁,避免「看似小问题、实则大故障」的复现。