适用于使用 glibc 与 systemd-resolved 的 Linux 主机,命令基线为 systemd 245+、iproute2 5.5+;dig 来自 Debian/Ubuntu 的 dnsutils 或 RHEL 系的 bind-utils,属于可选工具。示例域名、接口和 DNS 地址都必须替换为实际值。先采集失败窗口,不要一开始就改写 /etc/resolv.conf 或清空缓存。
1. 从原始失败环境固定证据
在出现问题的同一主机、容器或网络命名空间内执行:
date -u
getent ahosts api.example.com
resolvectl query api.example.com
readlink -f /etc/resolv.conf
sed -n '/^[[:space:]]*hosts:/p' /etc/nsswitch.conf
getent 走应用常用的 NSS 路径,结果会受 nsswitch.conf、本地文件和解析模块影响;resolvectl query 观察 systemd-resolved 的决策。两者结果不同,优先检查 NSS 顺序、容器内配置以及应用是否使用自己的解析器。应保留应用原始错误:超时、SERVFAIL、NXDOMAIN 和临时解析失败指向的分支不同。
若系统未运行 systemd-resolved,resolvectl 失败不等于 DNS 故障,应按实际使用的 NetworkManager、容器运行时或本地缓存程序继续检查。
2. 确认配置来源与每链路 DNS
systemctl is-active systemd-resolved
resolvectl status
ip -br link
ip route
ss -lunp '( sport = :53 )'
重点记录目标接口的 DNS Servers、DNS Domain、DefaultRoute 与当前默认路由。/etc/resolv.conf 指向 127.0.0.53 时,它只是本机 stub,真实上游应从 resolvectl status 查看。若同一域名只在 VPN 接入后失败,检查路由域是否配置为 ~corp.example 一类的分流域,以及查询是否被送到预期接口;不要只把公共 DNS 写入文件,这可能破坏内部域名解析。
3. 分别验证上游、UDP 与 TCP
有 dig 时,对实际上游逐个执行:
dig @DNS_IP api.example.com A +time=2 +tries=1
dig @DNS_IP api.example.com AAAA +time=2 +tries=1
dig @DNS_IP api.example.com A +tcp +time=2 +tries=1
直接查询上游成功而 getent 失败,问题更靠近本机 NSS、stub 或缓存;所有上游都超时,再查路由、防火墙和上游可达性。UDP 超时但 TCP 成功,或较大响应才失败时,应检查 53/UDP 策略、响应截断、EDNS 与路径 MTU。一次成功不足以排除间歇故障,应在故障窗口对同一上游做有限次数采样,并记录每次 UTC 时间和返回码。
4. 对齐日志、统计与报文
resolvectl statistics
journalctl -u systemd-resolved --since '-15 min' --no-pager -o short-iso
sudo tcpdump -ni any '(udp port 53 or tcp port 53)' -c 100
抓包时同时触发一次受控查询。只有请求没有响应,继续沿目标上游和回程排查;收到 SERVFAIL 或 NXDOMAIN,应保留响应方地址并检查权威记录、DNSSEC 或分流配置;有响应但应用仍报错,则回到 NSS、应用缓存和网络命名空间。抓包可能包含查询名称和地址,应限制包数并对公开输出做必要脱敏。统计项是累计值,应比较同一服务启动周期内的前后增量,不要把单次总数当作当前故障率。
5. 排除容器与宿主机视角差异
宿主机解析成功不能证明容器内成功。应进入实际工作负载执行 getent ahosts api.example.com,并检查其 /etc/resolv.conf;若只能从宿主机定位,可先确认目标进程 PID,再在其网络命名空间只读验证:
readlink /proc/1/ns/net /proc/PID/ns/net
sudo nsenter -t PID -n getent ahosts api.example.com
nsenter 来自 util-linux,执行前必须确认 PID 属于目标进程。容器中的 127.0.0.53 若没有对应本地 stub,通常是配置传递错误,不能用宿主机上的监听状态代替判断。
6. 闭环验证
每次只修改一个有证据支持的配置项。完成后从最初失败的应用入口重复无副作用请求,并同时确认:
getent ahosts api.example.com
resolvectl query api.example.com
resolvectl statistics
验证窗口应覆盖原先的失败周期;结果需显示查询被送到预期链路和上游,应用错误不再新增,超时或失败计数不再随受控请求增长。仅执行一次 dig 成功,不能证明应用实际解析路径已经恢复。