根本问题是宿主机多网卡导致路由混乱:存在多个默认网关或docker0与业务网段重叠,使容器流量被错误导向docker0或非业务网卡;需清理冲突路由、修改bip避开重叠、配置snat并启用ip_forward。

根本问题不在 Compose 本身,而在宿主机多网卡引发的路由混乱——Docker 容器(尤其是 bridge 模式)依赖宿主机的默认路由和 NAT 规则出外网,一旦宿主机存在多个默认网关或子网重叠,流量就可能被导向 docker0 或错误网卡,造成“容器能 ping 通宿主机但上不了外网”的典型隔离现象。
清理宿主机重复默认路由
多网卡宿主机常因 Docker 启动时自动添加 default via 172.17.0.1 dev docker0,与业务网卡的 default via 192.168.5.1 dev ens33 并存,触发内核路由模糊匹配:
- 运行 ip route,确认是否出现两条及以上
default via ... - 临时删除冲突路由:sudo ip route del default via 172.17.0.1
- 永久解决:在启动 Docker 前,确保宿主机仅保留一条指向业务出口网卡的默认路由(如
default via 192.168.5.1 dev ens33)
避开 docker0 与业务网段地址冲突
Docker 默认使用 172.17.0.0/16,若宿主机业务网段是 172.17.10.0/24 或 172.16.0.0/12,内核会优先匹配更长前缀的 docker0 子网,导致本该走物理网卡的包被截留在网桥内:
- 编辑 /etc/docker/daemon.json,指定不重叠网段:{"bip": "192.168.200.1/24"}
- 停服务:sudo systemctl stop docker containerd
- 删旧网桥:sudo ip link delete docker0
- 重启 Docker:sudo systemctl start docker
- 验证:ip addr show docker0 应显示新 IP,且 ip route 中对应子网已更新
强制容器流量经指定业务网卡出口
仅靠默认路由不够。当宿主机有 eth0(内网)、eth1(公网)等多张业务网卡时,需显式控制容器出向流量路径:
- 确认容器所在网桥的宿主机侧 IP(如 192.168.200.1),该 IP 必须属于你希望出口的网卡子网,或能被其网关转发
- 添加 SNAT 规则(以走 eth1 为例,其 IP 为 203.0.113.10):sudo iptables -t nat -A POSTROUTING -s 192.168.200.0/24 -o eth1 -j SNAT --to-source 203.0.113.10
- 开启内核转发:echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward,并写入 /etc/sysctl.conf 持久化
检查 Compose 网络模式与 DNS 配置
bridge 模式下容器完全依赖宿主机路由;host 模式则直接暴露宿主机多网卡路由问题,更容易复现故障:
- 避免在 docker-compose.yml 中混用
network_mode: host和networks:声明,二者互斥 - 若使用自定义网络,确保未遗漏
driver: bridge及子网声明,防止回退到默认 bridge(无 DNS 解析) - 在容器内执行 cat /etc/resolv.conf,确认 DNS 服务器可访问;若不可达,按需在 daemon.json 或 compose 文件中配置
dns:字段











