Docker 容器能够访问 IP 地址,却偶尔提示 “Temporary failure in name resolution” 或 “Could not resolve host”,通常意味着网络链路基本正常,故障集中在 DNS 查询环节。🔍 间歇性问题尤其难排查,因为它可能同时受到宿主机解析器、Docker 内置 DNS、VPN、防火墙和上游服务器稳定性的影响。本文提供一套从现象确认到长期修复的排查流程。
一、先判断是否确实为 DNS 故障
不要看到域名访问失败就直接修改 resolv.conf。应先在故障容器中分别测试 IP 连通性和域名解析,区分路由、代理、TLS 与 DNS 问题。
docker exec 容器名 ping -c 3 目标IP
docker exec 容器名 getent hosts example.com
docker exec 容器名 nslookup example.com
如果 IP 可以访问,而 getent 或 nslookup 间歇性超时,问题大概率位于 DNS 链路。如果 IP 同样不可达,则应优先检查容器网关、路由、iptables、nftables、安全组或宿主机转发设置。部分精简镜像没有 ping、dig 或 nslookup,可临时使用带网络工具的诊断容器,避免为了排错直接改动业务镜像。
二、理解容器中的 resolv.conf 从哪里来
容器内的 /etc/resolv.conf 通常由 Docker 在创建容器时生成,并不是镜像中的普通静态文件。默认 bridge 网络与用户自定义网络的解析行为可能不同:连接用户自定义网络的容器通常通过 Docker 内置 DNS 完成容器名称发现,再将外部域名查询转发给上游解析器。Docker 官方对容器网络及 DNS 行为有专门说明,可参考 Docker 网络文档。
先对比宿主机和容器中的配置:
cat /etc/resolv.conf
docker exec 容器名 cat /etc/resolv.conf
docker inspect 容器名
重点观察 nameserver、search 和 options。如果容器中出现 127.0.0.11,通常表示正在使用 Docker 内置 DNS;如果出现 127.0.0.1 或其他仅在宿主机回环接口监听的地址,容器网络命名空间往往无法直接访问它。
三、常见的间歇性失败原因
1. 宿主机本地解析器不可从容器访问
部分 Linux 系统使用 systemd-resolved,本机应用可能通过回环地址访问存根解析器。若 Docker 获得了不可从容器访问的本地地址,容器查询就可能失败。应通过 resolvectl status 查看实际使用的上游 DNS,并检查 /etc/resolv.conf 是普通文件还是软链接,而不是简单复制其中的回环地址。
2. VPN 或公司网络动态改写 DNS
VPN 建立和断开时,NetworkManager、systemd-resolved 或企业安全客户端可能更新 DNS 与搜索域。已经运行的容器不一定立即获得符合预期的解析路径,于是出现“刚启动正常,网络切换后失败”的现象。此时可记录故障前后的 resolvectl 输出,并在 VPN 切换后重新创建测试容器进行对比。
3. UDP 53 被丢弃或连接跟踪异常
DNS 通常优先使用 UDP,响应过大或被截断时可能切换到 TCP。若防火墙只允许 UDP 53、只允许 TCP 53,或者 NAT 与连接跟踪表压力过高,就可能表现为随机超时。🧱 排查时应同时测试 UDP 和 TCP 查询,并查看宿主机防火墙规则及内核日志。
4. 搜索域和 ndots 导致多余查询
resolv.conf 中的 search 与 options ndots 会影响短名称的查询顺序。搜索域较多或 ndots 设置不合适时,一个业务请求可能触发多次 DNS 查询,从而放大上游延迟。应优先使用完整域名进行对照测试,再根据实际服务发现需求调整配置,不要盲目删除企业内部搜索域。
四、按层次执行排查
- 容器层:连续执行多次 getent 或 nslookup,记录成功率、响应时间和具体错误;同时查看容器内 resolv.conf。
- 网络层:分别在默认 bridge 与用户自定义网络中启动临时容器,判断问题是否与特定 Docker 网络有关。
- 宿主机层:使用 resolvectl status、ss 和防火墙查询命令确认解析器监听地址及 DNS 流量是否放行。
- 上游层:分别向当前上游 DNS 发起查询,比较 UDP、TCP、内网域名和公网域名的结果。
- 时间维度:将失败时间与 VPN 切换、网络重连、Docker 重启、DHCP 续租及配置发布记录对应起来。
需要抓包时,可在宿主机执行:
tcpdump -ni any port 53
如果能看到容器发出查询却没有响应,应继续检查上游 DNS、路由和防火墙;如果完全看不到查询,则问题更可能位于容器解析库、Docker 内置 DNS 或容器网络配置。
五、选择合适的修复方式
临时验证可以在启动容器时指定可达的 DNS:
docker run --dns DNS服务器地址 镜像名
若验证有效,可在 Compose 服务中配置 dns,或在 /etc/docker/daemon.json 中设置 Docker 守护进程的全局 DNS。修改 daemon 配置前应先备份文件并校验 JSON 格式,随后重启 Docker。需要注意,重启服务可能影响正在运行的容器,生产环境应安排维护窗口。相关参数以 来源链接 官方参考为准。
不要把公共 DNS 当成所有场景的固定答案。企业内网域名、分流 DNS 和 VPN 私有区域通常只能由指定解析器回答。正确做法是选择容器网络能够访问、同时具备所需域名区域权限的 DNS,并准备合理的备用解析器。
- 单个服务有特殊需求时,优先使用容器或 Compose 级配置。
- 所有容器都受影响时,再考虑 Docker daemon 全局配置。
- 宿主机本身也解析异常时,应先修复 NetworkManager 或 systemd-resolved。
- 不要长期在容器启动脚本中覆盖 resolv.conf,这容易掩盖网络平台问题。
- 配置修改后应重新创建容器,并再次检查实际生成的 resolv.conf。
六、建立可持续的监控
✅ 修复完成后,应从容器所在网络持续探测关键域名,记录解析耗时、超时次数、返回码和所用 DNS 服务器。告警应区分“域名不存在”“查询超时”和“服务器失败”,否则排障人员仍然只能看到笼统的连接错误。
日志中还应保留 Docker 网络名称、容器启动时间、宿主机 DNS 配置变更和 VPN 状态。这样再次发生间歇性故障时,可以快速判断是单容器、单宿主机、特定网络还是上游解析服务的共同问题。
总结
Docker 容器 DNS 间歇性失败不能只靠修改 resolv.conf 解决。可靠的处理顺序是:先证明 IP 网络正常,再确认容器实际使用的解析器,随后检查 Docker 内置 DNS、宿主机解析服务、VPN、防火墙和上游服务器。修复时应按影响范围选择容器级或 daemon 级配置,并通过连续查询、抓包和监控验证结果。只有把 DNS 查询的完整路径梳理清楚,才能避免问题在下一次网络切换或容器重建后再次出现。🛠️