在 Docker 环境中,宿主机访问网站正常,容器里却出现“Temporary failure in name resolution”“Could not resolve host”或软件源更新失败,通常意味着 DNS 查询链路存在异常。问题可能来自宿主机解析器、Docker 内置 DNS、网络策略、代理环境,也可能只是容器继承了不可用的 DNS 地址。下面按“先定位、后修复”的顺序梳理一套实用排查方法。🔍
一、先确认是否真的是 DNS 故障
不要看到网络请求失败就立即修改 DNS。首先进入容器,分别测试 IP 连通性和域名解析。如果访问公网 IP 正常,而访问域名失败,才可初步判断为 DNS 问题。
- 执行 docker exec -it 容器名 sh 进入容器。
- 执行 ping -c 3 1.1.1.1 测试基础网络连通性。
- 执行 ping -c 3 example.com 或 nslookup example.com 测试域名解析。
- 若镜像没有 ping、nslookup,可通过 getent hosts example.com 或应用自身的 curl、wget 命令辅助判断。
如果 IP 和域名都无法访问,应优先检查容器默认路由、Docker 网桥、宿主机转发规则、防火墙和出口网络。只有 IP 可达而域名不可解析时,才应把重点放在 DNS 配置上。✅
二、检查容器实际使用的 DNS
进入容器后执行 cat /etc/resolv.conf,重点查看 nameserver、search 和 options。默认 bridge 网络中的容器通常会继承宿主机相关的 DNS 配置;连接用户自定义网络时,Docker 还会通过内置 DNS 提供容器名称解析。用户自定义网络支持容器通过名称互相通信,相关机制可参考 Docker 网络文档。citeturn1search3
如果 resolv.conf 指向 127.0.0.1 或其他仅在宿主机本地有效的监听地址,容器通常无法直接访问该解析服务。部分系统使用本地 stub resolver,宿主机上的回环地址并不等同于容器自身的回环地址。此时应找到上游 DNS,或配置容器可访问的实际 DNS 服务器。
注意:不要仅凭 resolv.conf 中出现特殊地址就认定 Docker 异常,还要结合容器所属网络、DNS 查询结果和宿主机配置综合判断。
三、按层级定位故障范围
1. 对比宿主机与容器
在宿主机执行 getent hosts example.com,再在容器中执行相同测试。若宿主机也失败,应先修复系统 DNS、VPN、代理或网络出口;若只有容器失败,则继续检查 Docker DNS 和网络规则。
2. 使用临时容器复现
执行 docker run --rm busybox nslookup example.com。如果新容器同样失败,问题更可能位于 Docker 守护进程或宿主机网络层;如果只有某个业务容器失败,应检查该容器的启动参数、Compose 配置、网络模式和镜像内部设置。
3. 区分公网域名与容器名称
公网域名无法解析,多与上游 DNS、53 端口访问或转发链路有关;只有服务名无法解析,则要确认相关容器是否加入同一个用户自定义网络。默认 bridge 网络不适合依赖容器名称发现,建议为同一应用栈创建专用网络。🐳
四、为单个容器指定自定义 DNS
临时验证时,可在启动容器时添加 --dns DNS服务器地址,多个 DNS 可重复设置。例如先指定企业内部 DNS,再设置允许使用的备用 DNS。Docker 守护进程也提供 dns、dns-opt 和 dns-search 等配置项,具体参数可查看 dockerd 参数说明。citeturn1search2
使用 Docker Compose 时,可在对应服务下设置 dns 列表,也可根据内部域名需要设置 dns_search。修改后应重建容器,而不是只重启旧容器,因为 DNS 参数属于容器创建配置。可执行 docker compose up -d --force-recreate 使设置生效。
自定义 DNS 不应盲目填写公共地址。企业内网域名、私有云服务发现或 VPN 域名通常必须通过内部 DNS 解析;如果强制改为公共 DNS,可能导致外网恢复但内部服务失效。🔧
五、配置 Docker 全局 DNS
如果所有容器都需要相同的上游 DNS,可修改 Docker 守护进程配置。Linux 常规安装默认使用 /etc/docker/daemon.json,rootless 模式通常使用 ~/.config/docker/daemon.json。Docker 推荐通过 JSON 配置文件集中管理守护进程设置,详见 Docker daemon 配置文档。citeturn1search1
在 daemon.json 中加入 dns 数组后,先执行 dockerd --validate --config-file=/etc/docker/daemon.json 检查格式,再执行 systemctl restart docker。重启 Docker 可能影响正在运行的容器,生产环境应提前安排维护窗口。已有容器也可能需要重新创建,才能稳定采用新配置。
此外,不要同时在 daemon.json 与 dockerd 启动参数中重复定义同一选项,否则守护进程可能因配置冲突而无法启动。遇到重启失败,可运行 systemctl status docker 和 journalctl -u docker 查看日志。相关冲突处理可参考 Docker 守护进程排障文档。citeturn1search6
六、常被忽略的网络因素
- 防火墙限制:确认容器到 DNS 服务器的 UDP 53 和 TCP 53 流量未被阻断,大响应或回退查询可能使用 TCP。
- VPN 与办公网络:连接 VPN 后,路由和 DNS 搜索域可能变化,Docker 启动时继承的配置也可能过期。
- systemd-resolved:确认宿主机实际的上游 DNS,而不是直接把仅监听本机回环地址的 stub 地址交给容器。
- 代理配置:HTTP 代理异常与 DNS 故障表现相似,可使用 nslookup 或 getent 将两者区分。
- IPv6 问题:如果域名能解析但连接长时间等待,应检查应用是否优先使用不可达的 IPv6 地址。
- iptables 或 nftables:自定义安全规则可能破坏 Docker 的转发和 NAT 链路,修改后应核对规则顺序。
七、推荐的排查顺序
建议依次执行:确认宿主机解析正常、测试容器访问 IP、检查容器 resolv.conf、使用临时容器复现、指定单容器 DNS 验证、检查网络与防火墙、最后再调整 Docker 全局 DNS。这样可以减少无目的修改,也方便在每一步保留证据并快速回滚。🧭
总结
Docker 容器 DNS 解析失败并不等于“换一个公共 DNS 就能解决”。可靠的处理方式是先区分网络不可达与域名解析失败,再判断故障位于宿主机、Docker 守护进程、容器网络还是应用配置。单容器参数适合快速验证,全局 daemon.json 适合统一治理,企业内网则应优先保证内部 DNS 和搜索域可达。修改后务必重建测试容器并复查解析结果,才能确认问题真正闭环。🚀