文章目录引言一、DNS 为什么要分层二、一次完整的递归查询长什么样DNS 记录类型速查三、生产环境里的四个典型 DNS 故障3.1 DNS 缓存投毒与 DNS 劫持3.2 缓存记录陈旧TTL 的 min-footer 陷阱3.3 NS 记录配置错误子域 delegation 失效3.4 VPC 内网 DNS 服务器的隐性覆盖四、Kubernetes 集群内的 DNS 解析4.1 集群 DNS 架构4.2 两种 Service 的解析差异4.3 端到端 DNS 调试路径五、总结DNS 故障的定位框架引言凌晨两点告警响起支付服务无法调通第三方渠道。开发人员登录服务器curl出去的域名报Could not resolve host。第一反应是对方挂了但dig一查域名解析正常。再深入追发现/etc/resolv.conf里的 DNS 服务器 IP 指向了一个早已失效的内部地址——服务重启后残留的 DNS 配置恰好覆盖了新下发的 DNS 服务器。这类问题在生产环境里频繁出现。DNS 故障难定位根本原因在于DNS 是一套分层递归系统任意一层的配置或数据出错都会导致最终解析失败但错误往往在距离故障点很远的地方才被触发。一、DNS 为什么要分层DNS 的核心设计哲学是分治。全球数十亿台主机不可能维护一份完整的域名到 IP 的映射表。解决方案是把这份映射分散到层级不同的权威服务器上每台服务器只对自己负责的 zone 享有最终解释权。层级结构如下权威服务器层递归解析层客户端1. 查询2. 根查询3. 返回 .com NS4. 查询 .com5. 返回 example.com NS6. 查询7. 最终答案8. 返回Stub Resolver(glibc / musl)Full Resolver(DNS 缓存服务器)例114.114.114.114223.5.5.5VPC 内网 DNS根服务器(全球 13 组).com .cn .netTLD 服务器权威 NS(example.com)根服务器Root全球共 13 组a-m.root-servers.netIP 地址固定在代码里。负责返回顶级域TLD的 NS 记录。TLD 服务器管理.com.cn.org等顶级域的权威解析。.com由 Verisign 运营.cn由 CNNIC 运营。权威服务器Authoritative NS具体域名如api.example.com的最终答案在这里。注册域名时在域名注册商处填写的 DNS 服务器就是这一层。递归解析器Full Resolver不是权威服务器是替客户端跑腿的中间人。它接收客户端查询依次向上层发起请求缓存结果最终把答案返回给客户端。家庭路由器、ISP DNS、公共 DNS 服务114.114.114.114 / 223.5.5.5 / 8.8.8.8都属于这一层。二、一次完整的递归查询长什么样以查询www.example.com为例dig trace把整个过程展开如下# 完整路径追踪digtrace www.example.com A short输出大致分为三个阶段第一阶段——根查询. 518400 IN NS a.root-servers.net. a.root-servers.net. 3600000 IN A 198.41.0.4递归解析器从内置的根服务器地址出发向根服务器查询www.example.com根服务器返回负责.com的 TLD 服务器地址。第二阶段——TLD 查询com. 172800 IN NS a.gtld-servers.net. a.gtld-servers.net. 172800 IN A 192.5.6.30递归解析器拿着a.gtld-servers.net的地址去问它www.example.com在哪里。TLD 服务器返回example.com的权威 NS 地址。第三阶段——权威查询example.com. 86400 IN NS ns1.example.com. ns1.example.com. 172800 IN A 93.184.216.34 www.example.com. 86400 IN A 93.184.216.34递归解析器向ns1.example.com发起最终查询得到www.example.com对应的 A 记录93.184.216.34缓存这份答案返回给客户端。整个过程在网络良好的情况下耗时约10~100ms。缓存命中时递归解析器直接返回无需向上层发起请求延迟降至0~5ms。DNS 记录类型速查日常开发中最常打交道的是以下几类记录类型作用典型场景A域名 → IPv4 地址最常见的解析记录AAAA域名 → IPv6 地址IPv6 普及后的双栈场景CNAME域名 → 另一个域名www→ 主域名CDN 回源MX域名 → 邮件服务器邮件投递优先级TXT任意文本SPF 验证、域名所有权验证NS域名 → 权威 DNS 服务器域名 delegation关于 CNAME 的一个坑CNAME 记录不能和同一节点的 other records 共存。例如example.com不能同时有 A 记录和 CNAME 记录。这是因为 CNAME 意味着本节点的所有权归另一个域名与其他记录的定义冲突。三、生产环境里的四个典型 DNS 故障DNS 出问题时大多数人第一反应是网络不通。但 DNS 故障有它独特的指纹服务自身正常但域名解析失败。以下是四个高频故障的诊断路径。3.1 DNS 缓存投毒与 DNS 劫持这是最隐蔽的一类 DNS 故障。递归解析器向权威服务器发起查询时攻击者或 ISP 缓存服务器在响应包中掺入伪造的答案缓存后持续生效。客户端拿到的 IP 地址指向恶意服务器用户浑然不觉。诊断命令# 对比两个不同 DNS 服务器的解析结果dig8.8.8.8 www.example.com A shortdig114.114.114.114 www.example.com A short# 检查 DNS 响应是否被篡改通过检查 DNSSEC 状态dig8.8.8.8 www.example.com A dnssec cddnssec参数触发 DNSSEC 验证。如果返回结果中adauthentic data位被置上说明这条记录通过了 DNSSEC 校验答案可信。如果 DNSSEC 配置缺失或验证失败ad位不会出现在响应中。解决方案在内网或移动端使用 HTTPDNS通过 HTTP 协议直接查询腾讯/阿里的 DNS 解析服务绕过系统 DNS 解析路径或 DoHDNS over HTTPS/DoTDNS over TLS。DoH 将 DNS 查询封装在 HTTPS 请求里DoT 则用 TLS 直接传输中间网络设备无法感知或篡改查询内容。# 通过 DoH 查询curl Cloudflarecurl-shttps://cloudflare-dns.com/dns-query?namewww.example.comtypeA\-HAccept: application/dns-json|jq.# 通过 DoT 查询# 腾讯云 HTTPDNS SDK / Cloudflare 1.1.1.1 App 均支持 DoT3.2 缓存记录陈旧TTL 的 min-footer 陷阱DNS 记录有一个 TTLTime To Live值告诉递归解析器这份答案可以缓存多久。例如www.example.com. 3600 IN A 93.184.216.34TTL3600秒理论上这份记录在 1 小时后过期。但实际生产中记录过期后仍可能被递归解析器继续使用原因在于 RFC 2308 定义的negative cache TTL和DNS 服务器实现差异。某些递归解析器采用max(TTL, min-footer)策略。min-footer 是权威服务器在响应中附加的 SOA 记录最小值。如果 SOA 的minimum字段被设置为 5 分钟300 秒而实际 A 记录 TTL 为 1 小时那么保守的递归解析器会把这份记录多保留 5 分钟。更常见的坑是权威服务器修改了某条记录的 IP但大量递归解析器的缓存仍未过期。用户在故障后的几分钟甚至几小时内拿到的仍是旧 IP。# 查看权威答案加 noedns 跳过 EDNS避免干扰digns1.example.com www.example.com A noedns# 对比权威答案与本地递归解析器缓存的答案digwww.example.com A# 对比dig8.8.8.8 www.example.com A最佳实践修改 DNS 记录前提前将 TTL 降至一个较低的值如 300 秒等待一个 TTL 周期后再执行修改改完后再恢复原始 TTL。这一步被很多团队忽视直接导致 DNS 切换期间出现大量请求打到旧 IP。3.3 NS 记录配置错误子域 delegation 失效假设example.com在腾讯云注册DNS 解析也在腾讯云完成。此时ns1.example.com的 IP 地址由域名注册商统一管理与权威 NS 的配置是两套独立的系统。一个常见的失误是在腾讯云 DNS 控制台修改了 NS 记录但域名注册商处的 NS 服务器地址没有同步更新。此时全球的递归解析器仍向旧 NS 地址发起查询返回的是过期或错误的记录。# 查询域名的注册商处配置的 NS 服务器whois example.com|grepName Server# 对比 NS 记录与实际响应的 NS 是否一致digexample.com NS short两者必须完全一致。如果whois返回的 NS 与dig返回的 NS 列表不同说明 delegation 配置存在漂移。3.4 VPC 内网 DNS 服务器的隐性覆盖在云环境腾讯云 / AWS / 阿里云中VPC 内网的 DNS 解析通常由平台提供的地址提供例如腾讯云 VPC 内网 DNS 地址为183.60.83.19。但当 Docker 容器或 Kubernetes Pod 启动时如果/etc/resolv.conf被错误覆盖比如某个 Helm chart 在 values 中硬编码了8.8.8.8容器内的 DNS 查询会绕过平台 DNS 直接发往外部。后果容器内无法解析集群内部服务名my-service.default.svc.cluster.local但解析公网域名正常——这是一个极难排查的双重标准现象。# 检查容器内 DNS 配置cat/etc/resolv.conf# 从容器内查询集群内部服务名应返回 ClusterIPnslookupmy-service.default.svc.cluster.local# 对比直接查询平台 DNSdig183.60.83.19 my-service.default.svc.cluster.local A四、Kubernetes 集群内的 DNS 解析容器网络系列文章中遗留了一个关键问题Pod 内发出的 DNS 查询是如何到达 CoreDNS 的CoreDNS 又如何将服务名解析为 ClusterIP 或 Pod IP4.1 集群 DNS 架构kube-systemNodePodDNS Query/etc/resolv.conf负载均衡负载均衡结果结果Stub Resolver(glibc)指向 ndots:5Node Network(kube-ipvs / iptables)DNS 请求直接 IPVS 转发CoreDNS Pod #1CoreDNS Pod #2每个 Pod 的/etc/resolv.conf由 kubelet 管理内容大致如下nameserver10.96.0.10# kube-dns Service 的 ClusterIPsearch default.svc.cluster.local svc.cluster.local cluster.local options ndots:5ndots:5的含义是如果查询的域名中圆点数量少于 5 个就在查询前附加搜索域后缀。例如查询mysql先查mysql.default.svc.cluster.local4 个圆点不足 5 个触发搜索再查mysql.svc.cluster.local再查mysql.cluster.local最后查mysql本身这是一个常见的性能陷阱。在 Pod 内频繁查询短域名的服务如redis、mysql时每次查询会发出 4 条 DNS 请求加上搜索后缀穷举失败产生的 NXDOMAINDNS 服务器负载显著上升。解决方案是在 Kubernetes Service 定义中禁用搜索后缀注入或将ndots值调高设为0或一个较大的数让短域名直接走完整 FQDN 查询。4.2 两种 Service 的解析差异**ClusterIP Service普通 Service**的 DNS 记录指向一个虚拟 IPClusterIP由 kube-proxy 写入节点上的 iptables 或 IPVS 规则。Pod 访问该 Service 时请求首先命中这条 iptables 规则被 DNAT 转换为后端 Pod 的真实 IP。# 查看某 Service 对应的 iptables 规则iptables-tnat-LKUBE-SERVICES-n|grepmy-serviceHeadless ServiceclusterIP: None的 DNS 记录直接指向后端 Pod 的真实 IP 地址由 CoreDNS 通过 Kubernetes API 实时获取。这意味着 DNS 查询结果随 Pod 的增减动态变化没有 kube-proxy 中间的 DNAT 层。# headless service 示例apiVersion:v1kind:Servicemetadata:name:my-headlessspec:clusterIP:None# 声明为 Headless Serviceselector:app:my-appports:-port:80DNS 查询my-headless.default.svc.cluster.local返回的是后端 Pod 的 Pod IP 列表。这个特性使得 Headless Service 成为有状态应用StatefulSet的首选——每个 Pod 都有稳定的 DNS 域名和独立的网络标识。4.3 端到端 DNS 调试路径公网无法到达能到达答案错误集群内Pod 异常Pod 正常是查询仍失败Pod 内 DNS 查询失败公网域名还是集群内域名dig/nslookup指向本地 /etc/resolv.conf能否到达递归解析器检查 VPC 安全组出站规则对比多个递归解析器使用 DoH/DoT 绕过dig/nslookup指向 kube-dns ClusterIPCoreDNS Pod是否正常kubectl logs -n kube-system -l k8s-appkube-dns检查 Pod 重启原因检查 /etc/resolv.confndots 配置短域名查询是否触发搜索后缀Service 禁用搜索后缀注入或提高 ndots 阈值CoreDNS 缓存问题kubectl exec 进入 Pod直接 dig 10.96.0.10 查询五、总结DNS 故障的定位框架DNS 故障之所以难排查是因为它是一套链式系统答案在每一跳都可能被篡改或丢失。掌握以下四个问题定位效率会大幅提升第一问本地解析器有没有收到查询用dig或nslookup直接在出问题的机器上查询排除网络层面的连通性问题。第二问权威答案是正确的吗用ns1.example.com直接查询权威服务器对比递归解析器返回的答案是否一致。第三问是缓存陈旧还是查询被拦截对比不同递归解析器的结果检查 DoH/DoT 是否可用排除 DNS 劫持的可能性。第四问问题出在集群内还是集群外Kubernetes 环境下的 DNS 故障优先确认/etc/resolv.conf配置是否被意外覆盖CoreDNS Pod 是否健康运行。DNS 是生产系统的基础设施也是最容易在故障复盘时事后才想起来查的一环。将 DNS 纳入日常巡检TTL 是否合理、DoH 通道是否可用、CoreDNS 负载是否正常比在故障发生时临时排查要高效得多。