dig未返回ANSWER SECTION即解析失败:可能因本地DNS配置错误、域名未配置、DNS服务器不可达或拒绝递归查询;需用@指定DNS测试、+trace定位中断点、检查缓存及nsswitch.conf路径。

dig 命令没返回 ANSWER SECTION 就说明解析失败
遇到开发环境连不上某服务(比如 api.dev.example.com),先别急着查代码或网络策略,用 dig 看 DNS 层是否通。如果输出里压根没有 ANSWER SECTION,或者只有 NOERROR 但 ANSWER SECTION 为空,基本就是域名没解析出来——不是服务挂了,是根本没找到它在哪。
常见诱因包括:本地 /etc/resolv.conf 配置了错误的 DNS 服务器、目标域名在当前 DNS 上未配置、DNS 服务器本身不可达或拒绝递归查询。
- 先跑
dig api.dev.example.com @8.8.8.8 +short,绕过本地 DNS,直连公网 DNS 测试是否是本地配置问题 - 再跑
dig api.dev.example.com @127.0.0.53 +short(systemd-resolved 默认地址)或@127.0.0.1(dnsmasq / bind),确认本地 DNS 服务是否正常转发 - 如果
@8.8.8.8有结果但本地 DNS 没有,检查systemctl status systemd-resolved或resolvectl status,看是否启用了 fallback 或被覆盖
用 +trace 跟踪完整解析路径,定位卡在哪一级
dig +trace 不是“查缓存”,而是模拟 DNS 解析器从根服务器开始逐级问下去的过程。开发环境常因私有 DNS 层(比如公司内网 DNS、Consul DNS、CoreDNS)配置不一致导致解析中断,+trace 能一眼看出停在哪一层。
例如:dig api.dev.example.com +trace 输出中,如果最后几行反复出现 server can't find api.dev.example.com: NXDOMAIN,且查询目标是你们自己的 DNS IP(比如 10.10.20.10),那问题就在那个 DNS 上没配这条记录;如果卡在 .com 的权威服务器返回 REFUSED,可能是防火墙拦截了 UDP 53 或该服务器禁用了递归。
- 注意 +trace 默认走 UDP,某些企业防火墙会限制 UDP 查询长度,可加
+tcp强制 TCP 重试:dig api.dev.example.com +trace +tcp - 如果 +trace 中某一级返回
REFUSED或超时,说明那一级 DNS 拒绝响应或不可达,不是你本机的问题 - 避免在容器里直接跑 +trace——很多容器镜像没装完整 root hints,优先在宿主机或调试专用容器中执行
排查缓存污染和 TTL 导致的“改了 DNS 却不生效”
开发环境经常改完 DNS 记录(比如把 db.dev 指向新 IP),但应用还是连老地址。不是 DNS 没生效,是中间某层缓存没过期。Linux 本身不缓存 DNS,但 systemd-resolved、dnsmasq、甚至 Go 应用自带的 DNS 缓存(默认 30 秒)都可能拖后腿。
先确认当前实际查的是哪个 DNS:resolvectl query api.dev.example.com(systemd-resolved)或 dig api.dev.example.com +noall +stats 看 SERVER 行。再对比 dig api.dev.example.com @127.0.0.53 和 dig api.dev.example.com @8.8.8.8 的 ANSWER SECTION 是否一致、TTL 值是否不同。
- 清 systemd-resolved 缓存:
sudo resolvectl flush-caches;清 dnsmasq:sudo kill -SIGHUP $(pidof dnsmasq) - 查某条记录当前缓存的 TTL 剩余时间:
resolvectl statistics(看 Cache hit rate)或dig api.dev.example.com @127.0.0.53 +noall +answer,输出第一列数字就是剩余秒数 - Go 应用需设
GODEBUG=netdns=go绕过 cgo DNS,否则可能用 libc 缓存,行为更难预测
别忽略 /etc/nsswitch.conf 和 getent 的干扰
有些开发环境启用了 mdns4_minimal 或 resolve 模块,/etc/nsswitch.conf 里 hosts: 行顺序决定了系统调用 getaddrinfo() 时查什么——可能先查 mDNS(.local)、再查 systemd-resolved、最后才走 DNS。这时候 dig 显示正常,但 curl 或应用连不上,就是这个原因。
验证方法:运行 getent hosts api.dev.example.com,看返回是否和 dig +short 一致。如果不一致,说明 nsswitch.conf 配置让系统走了别的解析路径(比如文件 /etc/hosts、mDNS、甚至 LDAP)。
- 临时绕过所有 NSS 模块,强制只走 DNS:
getent -s dns hosts api.dev.example.com - 检查
/etc/nsswitch.conf中hosts:行是否含mdns4_minimal(尤其在 macOS 兼容开发机上常见),它会拦截所有.local域名,也可能误伤其他短域名 - 容器内若用
alpine镜像,getent默认不可用,改用nslookup或直接cat /etc/resolv.conf看 DNS 配置是否被覆盖
真正卡住的往往不是 dig 本身,而是你没意识到系统查 DNS 的路径有好几条:glibc 的 NSS、systemd-resolved 的 stub listener、容器网络的 DNS 注入、甚至应用层自建缓存。每次怀疑 DNS,先用 dig @明确IP 锁定 DNS 服务端行为,再用 getent 和 resolvectl 对齐客户端视角——两条线对不上,问题一定在线路中间某处。











