宿主机 curl 一切正常,进到容器里 ping 8.8.8.8 却超时,或者能 ping 通 IP 但 apt install 一直卡在"正在连接"——这是 Docker 使用中最典型的网络故障。更让人困惑的是:同一台宿主机上,有的容器能上网,有的不能;重启 Docker 服务后又莫名其妙好了。这些现象背后其实是三条彼此独立的链路在起作用:容器的网络模式决定了它走哪条路,宿主机的转发与 NAT 决定了流量能否出去,DNS 配置决定了域名能否解析。本文按这三条链路把 Docker 容器无法访问外网的排查方法完整梳理一遍,给出可直接复制执行的命令。
一、先理解默认 bridge 模式是怎么出网的
Docker 安装后会在宿主机创建一张名为 docker0 的 Linux 网桥,默认网段 172.17.0.0/16,网桥自身地址通常是 172.17.0.1。每启动一个使用默认 bridge 网络的容器,就会创建一对 veth pair(虚拟以太网设备对):一端放进容器里成为 eth0,另一端挂在 docker0 上。
容器访问外网的完整路径是:容器内 eth0 → veth → docker0 网桥 → 宿主机内核路由 → iptables NAT 表 POSTROUTING 链做 MASQUERADE(源地址伪装) → 宿主机物理网卡 → 外部网络。这条链条上任何一个环节断掉,表现都是"容器没有网络"。
# 查看宿主机上的网桥与容器 veth
ip addr show docker0
ip link show | grep -E 'docker0|veth'
brctl show # 需安装 bridge-utils
# 查看 Docker 有哪些网络
docker network ls
# 默认至少应有 bridge / host / none 三个
# 查看默认 bridge 的详细配置(子网、网关、MTU、连接的容器)
docker network inspect bridge
# 只看关键信息
docker network inspect bridge --format '{{.IPAM.Config}} {{.Options}}'
# 查看某个容器用的什么网络模式
docker inspect <容器名或ID> --format '{{.HostConfig.NetworkMode}}'
docker inspect <容器名或ID> --format '{{json .NetworkSettings.Networks}}' | python -m json.tool
二、分层测试:精确定位断在哪一层
不要一开始就重启 Docker。先跑一个干净的测试容器,按四层顺序测,能立刻把问题范围缩小到一个点。
# 起一个带完整网络工具的临时容器(用完即删) docker run -it --rm --network bridge busybox sh # 在容器内按顺序执行: # 第 1 层:看自己有没有 IP 和网关 ip addr ip route # 应看到 eth0 有 172.17.0.x 的地址,默认路由指向 172.17.0.1 # 第 2 层:ping 网桥(验证 veth 与网桥连通) ping -c 2 172.17.0.1 # 第 3 层:ping 宿主机物理网卡 IP(验证宿主机没拦 ICMP) ping -c 2 192.168.1.10 # 第 4 层:ping 公网 IP(验证 NAT 与出口) ping -c 2 8.8.8.8 # 第 5 层:解析域名(验证 DNS) nslookup www.baidu.com getent hosts www.baidu.com # 第 6 层:TCP 层连通性(排除 ICMP 被禁的误判) wget -O- -T 5 https://www.baidu.com >/dev/null && echo OK
结果判定:
| 测试现象 | 断点位置 | 下一步 |
|---|---|---|
| 容器内没有 IP / eth0 DOWN | 容器网络命名空间或 IPAM 分配失败 | 重建网络:docker network rm 后重启 Docker |
| 能 ping 通 172.17.0.1,ping 不通 8.8.8.8 | 宿主机转发或 NAT 未生效 | 检查 ip_forward 与 MASQUERADE 规则 |
| 能 ping 通 8.8.8.8,解析不了域名 | DNS 配置错误 | 检查容器 resolv.conf 与 daemon.json dns |
| IP 通域名通,但 curl 超时 | 目标端口被封 / MTU 问题 / 代理问题 | 测 MTU、检查 http_proxy 环境变量 |
| host 网络正常,bridge 网络不通 | bridge 链路本身有问题 | 重建 docker0 网桥 |
三、网络模式:选错模式是最高频的原因
Docker 有四种主要网络模式,很多"不能上网"其实是选错模式造成的,特别是误用了 none 或自定义的内网 bridge。
| 模式 | 启动参数 | 能否访问外网 | 说明 |
|---|---|---|---|
| bridge(默认) | --network bridge | 可以 | 经 docker0 做 NAT 出网,最常用 |
| host | --network host | 可以 | 共享宿主机网络命名空间,无 NAT,性能最好但端口易冲突 |
| none | --network none | 不能 | 只有 lo 回环,完全隔离,用于纯计算任务 |
| container | --network container:NAME | 取决于被共享的容器 | 与指定容器共享网络命名空间 |
| 自定义 bridge | --network mynet | 可以 | 支持容器名互解析,推荐生产使用 |
# 创建自定义 bridge 网络并指定子网、网关、MTU
docker network create \
--driver bridge \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
--opt com.docker.network.driver.mtu=1450 \
mynet
# 用指定网络启动容器
docker run -d --name web --network mynet -p 8080:80 nginx:1.25
# 把已运行的容器接入另一个网络(网络可以在线变更)
docker network connect mynet web
docker network disconnect bridge web
# 排查时临时切到 host 网络做对照测试
docker run -it --rm --network host busybox ping -c 2 8.8.8.8
# 查看某个网络下挂了哪些容器
docker network inspect mynet --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
四、DNS 专项排查:能 ping IP 但不能解析域名
这是最容易被误判成"网络不通"的场景。Docker 在不同网络模式下 DNS 行为不一样,必须先看清容器里的 /etc/resolv.conf。
# 查看容器实际使用的 DNS
docker exec <容器> cat /etc/resolv.conf
docker inspect <容器> --format '{{.HostConfig.Dns}} {{.ResolvConfPath}}'
# 用户自定义 bridge 网络:nameserver 应为 127.0.0.11
# (Docker 内嵌 DNS 服务器,它再转发给守护进程配置的 DNS)
# 默认 bridge 网络:通常是宿主机 /etc/resolv.conf 的拷贝
四种修法,按影响范围从小到大:
# 方式 1:单个容器启动时指定(影响最小,优先级最高)
docker run -d --name app --dns 223.5.5.5 --dns 114.114.114.114 nginx
# 方式 2:写入 docker-compose.yml
# services:
# app:
# dns:
# - 223.5.5.5
# - 8.8.8.8
# 方式 3:全局配置 /etc/docker/daemon.json(对所有新容器生效)
cat > /etc/docker/daemon.json <<'EOF'
{
"dns": ["223.5.5.5", "114.114.114.114", "8.8.8.8"],
"dns-opts": ["timeout:2", "attempts:3", "rotate"],
"iptables": true,
"ip-forward": true
}
EOF
# 方式 4:确认宿主机自身 DNS 正常(容器内嵌 DNS 会依赖它)
cat /etc/resolv.conf
dig www.baidu.com +short
systemctl status systemd-resolved
# 修改 daemon.json 后必须重载并重启 Docker
systemctl daemon-reload
systemctl restart docker
# 注意:daemon.json 的 dns 只对"新创建"的容器生效
# 已有容器需要重建才能拿到新配置
一个常见陷阱:如果宿主机 /etc/resolv.conf 里写的是 nameserver 127.0.0.53(systemd-resolved 的存根),容器会继承这个地址,但容器内的 127.0.0.53 并不是宿主机的解析服务,于是解析全部失败。解决方式是显式配置公网 DNS,或者用 host 网络。
五、宿主机侧:转发、NAT、防火墙与 MTU
如果容器 ping 不通 8.8.8.8 但能 ping 通 172.17.0.1,问题一定在宿主机这一层。
5.1 IP 转发是否开启
# 必须为 1,为 0 则容器完全出不了网 sysctl net.ipv4.ip_forward cat /proc/sys/net/ipv4/ip_forward # 临时开启 sysctl -w net.ipv4.ip_forward=1 # 永久生效 echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-docker.conf sysctl --system # IPv6 场景 sysctl net.ipv6.conf.all.forwarding
5.2 iptables NAT 规则是否丢失
# 看 POSTROUTING 是否有 MASQUERADE 规则 iptables -t nat -L POSTROUTING -n -v --line-numbers # 正常应看到类似:MASQUERADE all -- 172.17.0.0/16 !172.17.0.0/16 # 看 FORWARD 链策略,若为 DROP 且没有放行规则,容器也出不去 iptables -nvL FORWARD # 看 Docker 自建链是否存在 iptables -t nat -L DOCKER -n iptables -L DOCKER-USER -n -v # 检查 daemon.json 里是否误关了 iptables grep iptables /etc/docker/daemon.json # 若为 false,Docker 不会写任何 iptables 规则,容器必然不能出网
如果 POSTROUTING 里完全没有 MASQUERADE 规则,通常有两种原因:一是 daemon.json 中 "iptables": false;二是宿主机重启后 Docker 服务启动顺序早于某些网络组件。重启 Docker 守护进程会重建这些规则,这也是"重启一下就好了"的根本原因:systemctl restart docker。
5.3 firewalld / ufw 冲突
CentOS/RHEL 上 firewalld 默认开启 MASQUERADE 限制,Ubuntu 上 ufw 默认拒绝 FORWARD,两者都会掐断容器出网。推荐做法是显式放行,而不是关掉防火墙。
# firewalld 场景 firewall-cmd --permanent --zone=public --add-masquerade firewall-cmd --permanent --zone=public --add-port=8080/tcp firewall-cmd --reload firewall-cmd --list-all # 或者把 docker0 加入 trusted 区域 firewall-cmd --permanent --zone=trusted --add-interface=docker0 firewall-cmd --reload # ufw 场景:编辑 /etc/ufw/default 或 /etc/default/ufw sed -i 's/^DEFAULT_FORWARD_POLICY=.*/DEFAULT_FORWARD_POLICY="ACCEPT"/' /etc/default/ufw # /etc/ufw/before.rules 的 *nat 段中确保有: # -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE ufw reload # 看 nftables 是否有冲突规则(新版系统 iptables 是 nft 兼容层) nft list ruleset | head -50
5.4 MTU 不匹配导致的"能 ping 不能下载"
这是最隐蔽的问题:小包能通,大包(HTTP 响应、TLS 握手)卡死。常见于宿主机用了 VXLAN、PPPoE 或云厂商的 overlay 网络(MTU 通常 1450,而 Docker 默认 1500)。
# 查看物理网卡 MTU
ip link show eth0
# 查看 docker0 MTU
ip link show docker0
# 对比后修正:在 daemon.json 中统一 MTU
cat /etc/docker/daemon.json
# { "mtu": 1450 }
# 或对单个网络指定
docker network create --opt com.docker.network.driver.mtu=1450 mynet
# 容器内实测最大不分片包(-M do 禁止分片)
ping -c 2 -s 1472 -M do 8.8.8.8
# 1472 + 28(IP+ICMP头)= 1500;若失败逐步减小到 1422(对应 1450)
六、标准排查步骤清单
- 确认容器网络模式:
docker inspect <容器> --format '{{.HostConfig.NetworkMode}}',排除误用 none。 - 容器内看 IP、路由:
ip addr、ip route,确认有 172.17.0.x 且默认网关为 172.17.0.1。 - 分层 ping:172.17.0.1 → 宿主机 IP → 8.8.8.8 → 域名,定位断点层。
- 若 IP 通域名不通:查容器
/etc/resolv.conf,在 daemon.json 里补dns与dns-opts。 - 若网关通外网不通:查
sysctl net.ipv4.ip_forward必须为 1。 - 查 iptables:
iptables -t nat -L POSTROUTING -n -v确认有 MASQUERADE,iptables -nvL FORWARD确认策略非 DROP。 - 查防火墙:firewalld 加
--add-masquerade,ufw 改DEFAULT_FORWARD_POLICY=ACCEPT。 - 若小包通大包卡:对比物理网卡与 docker0 的 MTU,统一后重启 Docker。
- 检查 daemon.json 是否被误配
"iptables": false或"ip-forward": false。 - 最后手段:
docker network prune清理无用网络,再systemctl restart docker重建 docker0 与全部规则。
# 一次性收集诊断信息(贴给同事或工单很有用)
echo '--- docker version ---'; docker version --format '{{.Server.Version}}'
echo '--- networks ---'; docker network ls
echo '--- ip_forward ---'; cat /proc/sys/net/ipv4/ip_forward
echo '--- nat ---'; iptables -t nat -S POSTROUTING
echo '--- forward ---'; iptables -S FORWARD
echo '--- daemon.json ---'; cat /etc/docker/daemon.json
echo '--- resolv ---'; cat /etc/resolv.conf
echo '--- docker logs ---'; journalctl -u docker --no-pager -n 50
小结
Docker 容器无法访问外网,九成以上问题落在四个地方:网络模式选错、DNS 配置错误、宿主机 ip_forward 未开、iptables/firewalld 拦截了转发。剩下的疑难杂症基本是 MTU 不匹配和自定义网络的路由冲突。按"容器内 → veth/网桥 → 宿主机转发 → NAT → DNS"这条链路逐层测试,比盲目重启 Docker 高效得多。
避坑建议:
- 生产环境用自定义 bridge 网络而非默认 bridge,自定义网络支持容器名互解析,且隔离性更好。
- 不要把
iptables设为 false,除非你非常清楚自己在自建网络方案。 - daemon.json 改完只对新建容器生效,老容器必须重建才能拿到新的 DNS / MTU 配置。
- daemon.json 必须是合法 JSON,一个多余逗号会导致 Docker 直接启动失败,改完用
cat /etc/docker/daemon.json | python -m json.tool校验。 - 不要长期用
--network host绕问题,它牺牲了端口隔离,多实例部署时必然冲突。 - MTU 问题优先怀疑 overlay/VPN 环境,特征是小包通、大文件下载卡在 0%。
- 排查时保留现场,别急着
systemctl restart docker,重启会重建规则、把可复现的问题藏起来。
延伸阅读:容器能上网但把宿主机磁盘写满,通常是日志没有做轮转,可继续了解 Docker 日志驱动的容量限制配置。
企业QQ咨询




