在 Kubernetes 集群中,DNS 解析链路通常由 CoreDNS 承担。Pod 查询集群内服务时由 kubernetes 插件直接应答,查询外部域名时则通过 forward 插件转发到上游 DNS。上游 DNS 往往是公共 DNS 或企业内网 DNS,一旦这些上游出现网络抖动、超时或不可达,CoreDNS 的默认行为取决于 forward 插件的配置。如果只配置了一个上游地址,该节点故障时会直接导致解析失败;如果配置了多个地址但没有开启或调整健康检查,请求可能仍会被持续发往故障节点,造成超时拖慢响应。因此,理解并正确配置上游 DNS 的故障切换机制,是保障集群服务稳定性的关键一步。

forward 插件如何识别上游故障并摘除节点
CoreDNS 的 forward 插件承担将请求转发给上游 DNS 服务器的任务。一个 forward 规则可以携带多个上游地址,例如 forward . 8.8.8.8 1.1.1.1。插件会维护每个上游的健康状态,当查询请求被转发后,如果上游返回网络错误、超时或者返回 SERVFAIL 等异常,对应上游的失败计数会累加。失败计数达到 max_fails 设定的阈值后,该上游会被标记为不健康,并在 expire 时长内暂时从可用列表里摘除,不再接收新的查询。到达过期时间后,CoreDNS 会在下一个健康检查周期重新尝试探测,探测成功则恢复该上游。这个机制简单有效,既避免了持续请求故障节点,又能自动恢复。
max_fails 默认值是 2,表示连续失败 2 次后摘除。expire 默认 10 秒,表示摘除后 10 秒内不再尝试使用该上游。health_check 默认 0.5 秒,是健康检查周期。policy 默认 random,可选 sequential、round_robin 和 random。不同的策略决定了请求如何选择健康上游:sequential 会优先选择列表中的第一个可用地址,第一个不可用时依次向后选择,适合主备架构;round_robin 在健康上游之间轮询,适合多台对等的 DNS 服务器;random 随机选择,延迟表现接近轮询但分布不均。对于需要明确主备关系的场景,建议使用 sequential,并确保列表顺序符合预期。
需要注意的是,摘除逻辑依赖于失败计数,而失败计数只有在插件实际转发并收到错误时才会增加。如果上游 DNS 只是响应非常慢但没有超时,请求会一直等待,可能需要依赖 read_timeout 或 write_timeout 来提前终止。此外,max_concurrent 配置的是与上游服务器的最大并发连接数,当并发过高时后来的请求可能排队或被拒绝,这也会影响故障切换的表现。因此在调整参数时应结合集群规模合理设置。
.:53 {
errors
health
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
forward . 10.10.10.53 10.10.20.53 {
max_concurrent 1000
policy sequential
health_check 2s
max_fails 3
expire 30s
}
cache 30
loop
reload
loadbalance
}多上游故障切换配置示例与生产建议
在 Kubernetes 中修改 CoreDNS 配置通常通过编辑 kube-system 命名空间下的 coredns ConfigMap 完成。下面是一个包含双上游和故障切换参数的完整 Corefile 片段。第一个上游使用内网 DNS 服务器 10.10.10.53,第二个使用 10.10.20.53,并将 policy 设为 sequential,这样正常情况下所有外部查询优先走第一个 DNS,只有它连续失败 3 次后才切换到第二个,避免频繁横跳。
保存 ConfigMap 后,如果 CoreDNS 开启了 reload 插件,它会自动重新加载配置;否则需要手动重启 CoreDNS Pod。通过 kubectl rollout restart deployment coredns -n kube-system 可以强制滚动重启。生产环境中建议同时配置 errors 和 log 插件,将转发错误记录到标准输出,便于后续排查。如果使用了 Prometheus,可以启用 prometheus 插件采集 CoreDNS 的请求延迟、错误率等指标,这些指标能辅助判断上游切换是否频繁发生。
NodeLocal DNSCache 是另一个常见的优化手段。它在每个节点部署一个本地 DNS 缓存,Pod 的解析请求先到本地缓存,再由本地缓存转发到 CoreDNS 或直接转发到上游。NodeLocal DNSCache 的配置同样基于 CoreDNS,也使用 forward 插件,所以上游故障切换逻辑需要在其 Corefile 中单独设置。很多团队只修改了 CoreDNS 的配置,却忽略了 NodeLocal DNSCache 的上游列表,最后测试发现故障切换并没有按预期发生。因此在启用 NodeLocal DNSCache 的集群中,两处配置都要保持一致。
cluster.local:53 {
errors
cache 30
forward . 10.10.10.53 10.10.20.53 {
policy sequential
max_fails 2
expire 10s
}
}如何验证切换是否生效以及常见配置误区
验证故障切换最直接的方法是模拟上游故障。可以先在测试环境把第一个上游地址改成一个不可达的 IP,比如 10.255.255.1,第二个上游保持可用。然后从集群内启动一个临时 Pod,使用 nslookup ipipp.com 或 dig @10.96.0.10 ipipp.com 测试外部域名解析。正常情况下,即使第一个上游不可达,查询也会在短暂延迟后由第二个上游应答。查看 CoreDNS 日志可以看到类似 read udp ... i/o timeout 的记录,证明第一个上游被跳过。更精细的观察可以通过增加 log 插件打印每次转发的上游地址实现。
常见误区包括:只配置一个上游地址,故障切换无从谈起;把 max_fails 设得很大或 expire 设得很小,导致故障节点频繁摘除又恢复,产生抖动;把 policy 设为 random 却期望主备切换,random 并不保证顺序,主备效果无法稳定;不设置 health_check 时,摘除后的恢复可能需要等到自然过期,恢复速度较慢;还有团队把不同域的解析拆成多个 forward 段,但没有注意匹配顺序,导致某些查询始终命中第一个 forward 规则,预期外的上游从未被使用。配置多段 forward 时应结合域名后缀精确匹配,必要时使用 except 排除不需要转发的域。
最后,上游 DNS 故障切换只是高可用的一部分。还应该关注 CoreDNS 自身的副本数、Pod 反亲和性、资源限制以及节点网络策略。如果 CoreDNS 本身因为资源不足或节点故障不可用,即使上游切换再顺畅也无法完成解析。建议将 CoreDNS 部署为多个副本并分布在不同节点或可用区,同时为上游 DNS 的切换配置适当监控告警,当出现大量转发失败时及时介入处理。
Kubernetes DNSCoreDNS故障切换修改时间:2026-09-28 11:46:51