记一次 Kubernetes 集群因 CoreDNS 配置漂移导致服务发现间歇性失败的排查实录

一次 CoreDNS 配置漂移引发的服务发现间歇性故障:排查 DNS 解析延迟、缓存污染与配置不一致的根因定位与修复复盘。

问题背景

生产 K8s 集群(v1.28)自 8 月底节点滚动升级后,部分服务间调用开始出现间歇性超时与 5xx。监控显示 API 层延时正常,Pod 间网络连通性也无异常,但业务日志中「name resolution failed」「no such host」偶发出现。初步判断疑似 DNS 解析问题,但 CoreDNS Pod 本身健康检查与日志均无明显异常。

本次故障发生在业务高峰(09:30-11:30),平均每 15 分钟出现一次解析失败,持续约 2-3 分钟后自动恢复,属于典型的「间歇性、服务发现类」故障,对长连接与重试机制敏感的服务影响尤为明显。

故障现象

  1. 间歇性解析失败:业务 Pod 日志中出现 lookup xxx.svc.cluster.local: no such hosti/o timeout,频率约每 15 分钟一次,每次持续 2-3 分钟。
  2. CoreDNS 日志无明显异常coredns Pod 的 INFO 级别日志仅偶见 plugin/errors 记录,ERROR 级别日志为空。
  3. dig 测试结果不稳定:在故障窗口内,从业务 Pod 执行 dig +short xxx.svc.cluster.local @10.96.0.10 有时返回空,有时返回正确 IP,成功率约 60-70%。
  4. 缓存污染迹象:部分节点上 nslookup 结果与实际 Service Endpoint 不一致,怀疑存在缓存不一致或配置漂移。
  5. 无节点级网络故障pingtraceroutetcpdump 显示跨节点连通性正常,conntrack 表项也无异常。

排查过程

步骤 1:确认故障范围与时间窗口

首先通过 Prometheus 查询 coredns_dns_request_duration_secondscoredns_dns_responses_total 指标,发现故障窗口内 SERVFAILNXDOMAIN 响应比例显著上升(从常态 <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 发现配置与预期一致:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
.:53 {
    errors
    health {
        lameduck 5s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
        ttl 30
    }
    prometheus :9153
    forward . /etc/resolv.conf {
        max_concurrent 1000
    }
    cache 30
    loop
    reload
    loadbalance
}

但进一步检查发现,forward 插件指向 /etc/resolv.conf,而宿主机 /etc/resolv.conf 内容为:

1
2
3
nameserver 172.16.1.1
search company.local
options ndots:5

这意味着 CoreDNS 在无法解析 cluster.local 域时,会将请求转发到公司内网 DNS(172.16.1.1),而该 DNS 服务器对 cluster.local 无感知,会返回 NXDOMAIN 或超时。

步骤 3:定位配置漂移根源

进一步检查发现,CoreDNS Deployment 的 spec.template.spec.dnsPolicyDefault,而非推荐的 ClusterFirst。这导致 CoreDNS Pod 自身继承宿主机的 DNS 配置,而非使用 Kubernetes 内置 DNS。

同时发现,近期节点升级时,某批次节点 /etc/resolv.conf 被云平台初始化脚本覆盖,searchoptions 参数与集群不一致,导致部分 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 不一致,存在历史遗留配置。

解决方案

  1. 修复 CoreDNS Deployment 配置

    • dnsPolicy 改为 ClusterFirst,确保 CoreDNS 自身使用 Kubernetes DNS 解析。

    • forward 插件中明确指定上游 DNS,并添加 policy sequentialhealth_check

      1
      2
      3
      4
      5
      
      forward . 172.16.1.1 172.16.1.2 {
          max_concurrent 1000
          policy sequential
          health_check 5s
      }
      
  2. 清理与统一节点 DNS 配置

    • 通过 DaemonSet 在所有节点上统一 /etc/resolv.conf(使用 search cluster.local + options ndots:2),并通过 systemd-resolvedNetworkManager 锁定配置,防止云平台初始化脚本覆盖。
  3. 调整 CoreDNS 缓存策略

    • cache 30 改为 cache 15,降低 NXDOMAIN 污染窗口。
    • 启用 cache prefetch 机制,提前预热热点域名缓存。
  4. 增加健康检查与告警

    • 在 Prometheus 中增加 coredns_dns_responses_total{rcode="NXDOMAIN"}SERVFAIL 的告警规则,阈值设为 >1% 触发。
    • 部署 dnsutils Pod 作为「金丝雀」,每分钟执行一次 dig 测试并上报结果。
  5. 回滚与验证

    • 先在 3 个节点的小范围灰度集群上验证修复效果,确认解析成功率恢复至 99.9% 以上后,全量滚动更新 CoreDNS Deployment。

根因分析

根本原因在于 CoreDNS dnsPolicy 配置为 Default 导致继承宿主机 DNS 配置,叠加节点升级时 /etc/resolv.conf 被云平台脚本覆盖,引入了公司内网 DNS(对 cluster.local 无感知)作为上游。CoreDNS 在无法解析 cluster.local 域时转发至该上游,收到 NXDOMAIN 后缓存 30 秒,导致后续请求在缓存窗口内持续失败。

次要原因包括:

  • forward 插件缺少 health_checkpolicy 配置,无法快速剔除故障上游。
  • 节点 DNS 配置缺乏统一管理与锁定机制,存在配置漂移风险。

预防措施

  1. 配置即代码:将 CoreDNS 配置纳入 GitOps 仓库,通过 CI 校验 dnsPolicy 必须为 ClusterFirstforward 必须显式指定上游并启用健康检查。
  2. 节点 DNS 基线化:使用 DaemonSet + systemd-resolved 统一管理所有节点 /etc/resolv.conf,并通过 immutable 属性或 chattr +i 锁定关键配置。
  3. 监控全链路:在 kube-dnscorednsnode-dns 各层增加 NXDOMAINSERVFAILtimeout 指标告警,并部署「金丝雀」测试 Pod 实时验证解析可用性。
  4. 变更门禁:节点系统升级、云平台初始化脚本变更前,必须执行 DNS 解析回归测试(覆盖 cluster.local 与公司内网域名),并纳入变更结单证据包。
  5. 定期演练:每季度执行一次「DNS 配置漂移」应急演练,模拟上游 DNS 故障与缓存污染场景,验证回滚与修复流程。

总结

本次故障是典型的「配置漂移 + 缓存污染」复合场景:CoreDNS 因 dnsPolicy 配置不当继承了宿主机 DNS,节点升级时 /etc/resolv.conf 被覆盖引入公司内网 DNS,导致 cluster.local 解析间歇性失败。排查过程通过指标分析、配置比对、缓存验证三步定位根因,修复方案聚焦配置收口、缓存策略优化与监控告警三层面。

DNS 是 K8s 集群的「神经系统」,任何配置漂移都可能引发连锁反应。未来需将 DNS 配置纳入基线管理与变更门禁,避免「看似小问题、实则大故障」的复现。

使用 Hugo 构建
主题 StackJimmy 设计