在 Docker 环境中,容器可以访问外网,却无法访问宿主机某个地址;或者宿主机能访问容器,容器回包却丢失——这类问题通常不是单点故障,而是网络命名空间、路由表、网桥、防火墙与地址转换共同作用的结果。🔍 排查时不要急于重启 Docker 或清空防火墙,应沿着数据包的实际路径逐层定位。
一、先明确数据包经过的路径
桥接网络模式下,容器拥有独立的网络命名空间,其中包含网卡、IP 地址、路由表和协议栈。容器内的 eth0 通常通过 veth 设备与宿主机上的 Docker 网桥相连。数据包从容器发出后,大致依次经过:容器路由表、veth、宿主机网桥、宿主机路由决策、Netfilter 规则,最后到达目标接口。
Docker 的 bridge 驱动通常会在宿主机上配置网桥、转发规则和源地址伪装,使容器能够访问外部网络。不同 Docker 网络之间默认还会受到隔离规则约束,具体行为可参考 Docker Bridge 官方文档。因此,“容器网络不通”并不等同于“容器网卡有问题”。
二、确认故障范围和方向
排查前应先回答三个问题:是所有容器都不通,还是只有一个容器不通;是不通宿主机的全部地址,还是只不通某个接口地址;是单向不通,还是请求与响应都无法到达。✅ 这些现象可帮助区分容器配置、宿主机路由和防火墙问题。
- 测试容器网关:在容器中执行 ip route,找到默认网关,再使用 ping 或业务端口探测工具测试。
- 测试宿主机地址:分别测试 docker0 地址、物理网卡地址、回环地址对应的服务。
- 测试外部目标:同时测试纯 IP 地址和域名,避免把 DNS 故障误认为路由故障。
- 测试具体端口:ICMP 不通不一定代表 TCP 服务不可达,应使用 curl、nc 等工具验证实际端口。
三、检查容器网络命名空间
先执行 docker inspect 容器名,确认容器使用的网络模式、IP 地址、网关和网络名称。如果容器使用 none 模式,它不会获得常规网络连接;如果使用 host 模式,则不存在典型的独立桥接路径;如果使用 container 模式,则会共享另一个容器的网络栈。
进入容器后依次检查:ip addr、ip route、cat /etc/resolv.conf。正常情况下应能看到有效的 eth0 地址、容器网段路由以及默认网关。如果默认路由缺失、网关与容器不在同一子网,或网卡处于 DOWN 状态,应优先检查 Compose 文件、启动参数和 Docker 网络配置。
当容器镜像缺少 ip 等工具时,可以获取容器主进程 PID,再从宿主机执行 nsenter -t PID -n ip route。🧭 这种方式能够直接进入目标网络命名空间观察路由,而不必修改业务镜像。
四、核对宿主机网桥与路由表
在宿主机执行 ip addr、ip link 和 ip route,确认 docker0 或用户自定义网桥处于 UP 状态,并且存在指向容器子网的直连路由。随后通过 docker network inspect 网络名,对照网络的 Subnet、Gateway 与宿主机路由是否一致。
特别要关注网段冲突。例如 Docker 网络使用 172.18.0.0/16,而企业 VPN、云上 VPC 或物理网络也使用同一网段时,宿主机可能把数据包送往错误接口。此时即使容器网关正常,访问重叠网段仍会失败。处理方式是规划新的 Docker 地址池或重建自定义网络,而不是临时添加更多互相竞争的路由。
五、检查 IP 转发和防火墙规则
执行 sysctl net.ipv4.ip_forward,确认 IPv4 转发是否开启。Docker 的默认桥接网络依赖宿主机转发能力;如果该值为 0,跨接口的数据包无法正常通过。Docker 还会创建 DOCKER、DOCKER-USER、DOCKER-FORWARD 等链,并在 nat 表中配置端口映射和地址伪装,相关机制可查看 Docker 防火墙官方说明。
建议分别检查 iptables -S、iptables -t nat -S,以及 nft list ruleset。某些系统表面使用 iptables 命令,底层实际由 nftables 管理,因此只查看其中一套规则可能遗漏真实拦截点。⚠️ 不要直接执行 iptables -F 清空线上规则,这可能破坏端口映射、安全策略和远程连接。
自定义放行规则应优先考虑 DOCKER-USER 链,因为它用于在 Docker 转发规则之前处理用户策略。如果宿主机的 FORWARD 默认策略为 DROP,还要确认已有规则是否允许容器网桥与目标接口之间的双向流量。修改规则时应限定源网段、目的地址、端口和连接状态,避免无边界放行。
六、确认服务监听地址与回程路由
容器能 ping 通宿主机却访问不了服务,常见原因是服务只监听 127.0.0.1。宿主机的回环地址属于宿主机网络命名空间,容器中的 127.0.0.1 指向容器自身。可以执行 ss -lntup 检查服务监听地址;如需被容器访问,服务通常应监听宿主机网桥地址、指定物理接口地址或合适的通配地址,同时配合访问控制。
还要检查回程路由。请求可能成功到达宿主机或上游设备,但响应被策略路由、VPN 路由或多网卡默认路由送往另一接口。可使用 ip route get 目标地址查看内核实际选择的出口,并检查 ip rule 与各策略路由表。多网卡环境还应留意反向路径过滤设置是否与非对称路由冲突。
七、使用抓包确定丢包位置
如果静态配置看不出问题,应在链路两端同时抓包。先在容器网络命名空间观察 eth0,再在宿主机对应 veth、Docker 网桥和物理网卡上使用 tcpdump。📦 若容器 eth0 有请求而网桥无报文,重点检查 veth 和网络附加状态;若网桥有报文但物理接口没有,重点检查路由与 FORWARD 链;若请求已发出却没有响应,则检查对端防火墙和回程路由。
推荐排查顺序:
容器地址与默认路由 → 容器网关 → 宿主机网桥与路由 → 服务监听地址 → IP 转发 → 防火墙与 NAT → 回程路由 → 分接口抓包。
总结
Docker 容器与宿主机路由不通时,最有效的方法是按照数据包路径逐跳验证,而不是依赖重启或清空规则碰运气。先确认网络模式和故障方向,再核对命名空间、网桥、路由、转发、防火墙、监听地址及回程路径,最后通过抓包定位报文消失的位置。坚持“先观察、后修改,每次只改一个变量”,通常可以更快找到根因,也能避免排障操作引发新的网络故障。🛠️