跳到主要内容

技术教程

DNS 返回了错误 IP,还是服务真的不可达?一条可复核的诊断链

验证与风险信息

适用环境
CoreDNS 1.14.6 / Nginx 1.28.3 / Alpine 3.20 / Docker 24.0.7
验证耗时
约 10 分钟
风险与回滚
DNS 查询与绕过验证为低风险;修改权威记录前保存旧值与 TTL,并准备按记录集回滚
最后复核
2026-08-03
验证证据
同一后端通过 IP 直连成功;错误解析返回 192.168.250.99 后域名请求超时;修正为 192.168.250.10 后域名请求恢复。

应用提示“连接超时”时,服务不可达和 DNS 返回错误地址会表现得很像。只用浏览器刷新、重启应用或更换公共 DNS,既无法定位问题,还可能破坏企业内网的分域解析。诊断目标应当是回答四个问题:应用实际询问了哪个解析器、解析器返回了什么、绕过 DNS 后同一服务是否可达、权威记录与缓存何时会收敛。

适用范围与先给结论

本文适用于 Linux 主机、Docker 容器和常见 HTTP/HTTPS 服务的 A/AAAA 记录异常。V2CE 隔离实验使用 CoreDNS 1.14.6、Nginx 1.28.3 和 Alpine 3.20:一个解析器故意把 api.v2ce.test 返回到无人监听的地址,另一个解析器返回真实后端地址。

最有价值的对照不是“换一个 DNS 后好了”,而是:

  1. 从发生故障的同一网络命名空间查询域名,保存解析器、返回码、地址和 TTL;
  2. 保留原主机名与 HTTPS SNI,绕过 DNS 直接指定已知后端地址;
  3. 如果直接地址成功而域名失败,继续调查 DNS 记录、搜索域、缓存和分域策略;
  4. 如果两者都失败,再回到路由、防火墙、监听端口和应用状态。

第一步:从真正失败的位置取证

宿主机、容器、Pod 和浏览器可能使用不同解析链路。在宿主机执行 dig 不能代表容器内应用获得了相同结果。先进入故障进程所在环境,保存本机解析配置:

cat /etc/resolv.conf
getent ahostsv4 api.example.com
getent ahostsv6 api.example.com

# Docker
docker exec my-app cat /etc/resolv.conf
docker exec my-app getent ahostsv4 api.example.com

getent 经过系统名称服务开关,结果通常更接近应用实际调用 getaddrinfo() 时看到的地址;dig 则适合直接询问指定 DNS 服务器并观察协议字段。两者用途不同,不应互相替代。

第二步:查询应用使用的解析器

先从 /etc/resolv.confresolvectl status 找到实际解析器,再明确指定它:

dig @10.0.0.53 api.example.com A +noall +answer +authority +comments
dig @10.0.0.53 api.example.com AAAA +noall +answer +authority +comments
resolvectl query api.example.com

至少记录以下字段:

  • 状态码:NOERRORNXDOMAINSERVFAIL
  • 回答:A、AAAA 或 CNAME 最终指向的地址;
  • TTL:当前缓存还可能保留多久;
  • 解析器:回答来自哪个服务器,是否属于 VPN、公司内网或容器平台;
  • 搜索域:searchndots 是否把短名称改写成了其他查询。

NOERROR 不代表地址正确;它只表示服务器成功处理了查询。返回一个已下线、内网不可路由或端口未开放的地址,仍会让应用超时。

第三步:绕过 DNS,但保留主机名语义

HTTP 虚拟主机和 HTTPS 证书都依赖主机名。直接请求 https://1.2.3.4/ 会改变 Host、SNI 和证书校验,可能制造新的错误。使用 curl --resolve 指定地址,同时保留原域名:

curl -sv --connect-timeout 3 \
  --resolve api.example.com:443:203.0.113.20 \
  https://api.example.com/health

如果该请求成功,而普通域名请求仍失败,说明后端、目标端口、Host 路由和 TLS 在这条路径上基本可用,DNS 成为首要调查方向。如果 --resolve 也失败,应根据错误阶段继续检查 TCP、TLS、代理、ACL 和服务监听状态。

已知地址必须来自可信配置、负载均衡器或当前服务发现结果,不能随便从历史日志复制。对于多地址服务,应逐个测试并记录,因为只有某个地址失效也会造成间歇性错误。

第四步:区分错误地址、NXDOMAIN 与 SERVFAIL

返回错误 A/AAAA 地址

常见原因包括发布时写错记录、负载均衡器已更换、旧地址未删除、分域 DNS 配置不一致,以及客户端优先使用不可达的 IPv6 地址。对比应用解析器、权威服务器和另一网络视角的回答,确认差异发生在哪一层。

NXDOMAIN

NXDOMAIN 表示解析器认为该名称不存在。不存在结果也可能被缓存;RFC 2308 定义了 DNS 负缓存行为。因此刚修复记录后,部分客户端仍可能在负 TTL 窗口内继续失败。保存响应 authority 部分中的 SOA 和 TTL,不要用无限刷新判断传播是否完成。

SERVFAIL

SERVFAIL 表示解析器未能完成查询,可能与上游超时、DNSSEC 校验失败、权威服务器异常或策略拒绝有关。继续查看递归解析器日志,并用 dig +trace 作为辅助确认委派链;但要注意 +trace 从根开始迭代,不等同于应用所用递归解析器的真实缓存与策略。

第五步:确认权威记录与缓存边界

先找到权威服务器,再直接查询各权威节点:

dig example.com NS +short
dig @ns1.example.net api.example.com A +noall +answer +authority +comments
dig @ns2.example.net api.example.com A +noall +answer +authority +comments

如果权威服务器之间回答不一致,先修复区域发布或同步。若权威记录已一致而递归解析器仍返回旧值,依据旧响应的 TTL 等待或对受控缓存执行有范围的清理。不要重启所有网络服务,也不要长期修改 /etc/hosts 掩盖问题。

修复与回滚

修复前保存旧记录、TTL、变更单和当前查询结果。只修改错误的记录集;若要迁移地址,先在业务允许时提前降低 TTL,待旧 TTL 窗口结束后再切换。变更后从以下三个视角复核:

  1. 每台权威服务器返回相同的新记录;
  2. 应用正在使用的递归解析器返回新记录;
  3. 应用真实请求按域名成功,监控中的 DNS、连接和请求延迟恢复。

若新地址不可用,回滚到已验证的旧记录,并继续保留原 TTL 证据。DNS 回滚也受缓存影响,不是点击保存后全球瞬间生效。

V2CE 复现实验记录

实验后端固定为 192.168.250.10。故障客户端使用的解析器把 api.v2ce.test 返回为未使用的 192.168.250.99。同一客户端直接访问真实后端得到 v2ce dns lab backend ok,证明后端和容器网络可达;按域名访问则连接到错误地址并超时,退出码为 1。

恢复客户端使用的解析器返回 192.168.250.10 后,按同一域名访问立即得到相同正文。CoreDNS 日志同时记录了 A/AAAA 查询。这个对照证明本实验的直接故障点是错误 DNS 回答,而不是 Nginx 停止、后端端口关闭或客户端完全断网。

参考资料