Docker 容器无法访问外部网络 DNS 解析失败怎么排查

文章导读
Docker 容器无法解析域名通常是因为容器继承了宿主机无效的 DNS 配置,或者自定义网络缺少 NAT 转发规则。优先检查容器内 resolv.conf 文件并尝试指定公共 DNS 服务器。
📋 目录
  1. A 命令速用版
  2. B 为什么会这样
  3. C 分步处理
  4. D 怎么验证是否生效
  5. E 常见坑
A A

Docker 容器无法解析域名通常是因为容器继承了宿主机无效的 DNS 配置,或者自定义网络缺少 NAT 转发规则。优先检查容器内 resolv.conf 文件并尝试指定公共 DNS 服务器。

先说结论:大部分 DNS 故障源于容器内 DNS 服务器地址不可达,少数情况是宿主机 iptables 规则缺失导致外网完全不通。

  • 先确认:容器内 ping IP 是否通,区分是 DNS 问题还是网络链路问题
  • 先处理:通过 daemon.json 或启动参数强制指定可靠 DNS
  • 再验证:使用 nslookup 测试域名解析是否恢复

命令速用版

如果急需恢复业务,可以在启动容器时直接指定 DNS:

docker run `--dns` 8.8.8.8 `--dns` 114.114.114.114 -d your_image

若是已有容器,修改宿主机配置后重启 Docker 服务。注意:不要直接覆盖 daemon.json,以免丢失其他配置。

# 1. 备份原有配置
cp /etc/docker/daemon.json /etc/docker/daemon.json.bak

# 2. 编辑文件,确保 json 格式正确,添加 dns 字段
vi /etc/docker/daemon.json

# 3. 重启 Docker 服务
systemctl restart docker

为什么会这样

Docker 容器默认会继承宿主机的 DNS 配置,如果宿主机本身 DNS 波动或使用了本地递归服务(如 127.0.0.1),容器内可能无法正确解析。此外,自定义桥接网络需要 iptables 的 MASQUERADE 规则才能访问外网,若规则缺失,不仅域名无法解析,连 IP 也无法 ping 通。

关于容器内 /etc/resolv.conf 中的 127.0.0.11:这是 Docker 守护进程内置的 DNS 服务器,本身是有效地址。如果解析失败,通常是因为 Docker 守护进程自身无法向上游 DNS 发起请求,而不是容器内配置错误。

分步处理

1. 区分故障类型

进入容器内部,先 ping 一个公网 IP(如 8.8.8.8):

docker exec -it <container_id> ping 8.8.8.8

如果 IP 能通但域名不通,是纯 DNS 问题;如果 IP 也不通,检查网络模式及 iptables 规则。

Docker 容器无法访问外部网络 DNS 解析失败怎么排查

2. 检查容器 DNS 配置

查看容器内的 resolv.conf 文件:

docker exec -it <container_id> cat /etc/resolv.conf

如果 nameserver 指向宿主机无效 DNS 或解析超时,说明配置存在问题。若显示 127.0.0.11 但无法解析,需检查宿主机 Docker 服务状态。

3. 修正 DNS 配置

推荐在宿主机创建或编辑/etc/docker/daemon.json,写入全局 DNS。请务必先备份并合并原有配置:

{
  "dns": ["8.8.8.8", "114.114.114.114"],
  "其他原有配置": "保持不变"
}

修改后重启 Docker 服务使配置生效,新建容器将自动应用该配置。

4. 检查网络转发规则

如果 ping IP 也丢包,检查宿主机 iptables NAT 表是否有 MASQUERADE 规则:

Docker 容器无法访问外部网络 DNS 解析失败怎么排查
iptables -t nat -L POSTROUTING -n -v

若缺少相关规则,自定义网络有时需要手动补充规则或重启 Docker 服务重置网络。

同时检查网络模式详情:

docker network inspect bridge

确认 Options 中是否有 com.docker.network.bridge.enable_icc 等配置影响连通性。

怎么验证是否生效

在新启动的容器中执行解析测试:

docker run `--rm` alpine nslookup www.baidu.com

观察返回的 Address 是否为有效 IP,且没有 timeout 错误。同时检查应用日志中是否不再出现 getaddrinfo 相关报错。

常见坑

1. 宿主机 DNS 变动:如果宿主机通过 DHCP 获取 DNS,重启后可能变化,导致容器继承失效地址,建议在 daemon.json 中写死 DNS。

2. 自定义网络隔离:使用 docker network create 创建的桥接网络,若未正确配置网关和 NAT,容器无法出站。

3. 防火墙拦截:主机防火墙或安全组规则可能丢弃 UDP 53 端口流量,导致解析请求无法发出。