Docker Compose引发的网络冲突事件分析
本文记录了一次生产环境中Docker Compose网络配置导致的服务器连接问题,详细分析了问题现象、排查过程、冲突原理,并提供了临时和长期解决方案。通过这次事件,我们可以更好地理解Docker的网络模型和IP地址分配机制,以及如何在复杂网络环境中正确配置Docker网络。
问题现象
在一次执行docker compose up -d命令后,测试服务器突然无法连通。测试环境配置如下:
- 测试服务器拥有公网独立 IP,通过 TP-Link 路由器连接
- 服务器内网 IP 为
192.168.0.100 - 通过 VPN 连接路由器,VPN 分配的内网 IP 为
192.168.100.3
问题出现后,我的电脑可以连接 VPN,但无法连接到测试服务器。
排查过程
- 通过远程桌面连接到内网中的另一台机器
192.168.0.12 - 从该机器登录到测试服务器
192.168.0.100 - 在服务器上尝试 ping 本机 VPN IP:
ping 192.168.100.3 - 出现错误信息:
192.168.96.1 unreachable - 运行
ifconfig查看网络接口,发现192.168.96.1是 Docker Compose 创建的网卡 - 执行
docker compose down后,问题立即解决,网络恢复正常
原理解析
Docker 网络模型
Docker 默认使用三种网络模式:
bridge:默认网络模式,创建独立的网络命名空间host:容器使用主机网络栈none:容器没有网络连接
Docker Compose 创建的默认网络是一个 bridge 网络,它会为每个项目创建独立的网络命名空间。
IP 地址分配机制
Docker 在创建网络时有默认的 IP 分配机制:
- 优先使用
172.16.0.0/12网段 - 当 172 网段被占用或冲突时,会使用
192.168.0.0/16网段 - 在此案例中,Docker 选择了
192.168.96.0/20子网
冲突原因
问题的根本原因在于 Docker 自动选择的网段与我们的 VPN 网段产生了路由冲突:
- VPN 网段:
192.168.100.0/24(包含在192.168.96.0/20中) - Docker 网段:
192.168.96.0/20
当数据包尝试访问192.168.100.3时,Linux 路由表选择了 Docker 网络接口,而不是 VPN 接口,导致通信失败。
为什么外网连接也受到影响
这个路由冲突不仅影响内部通信,也导致外网无法连接到服务器的原因是:
路由决策问题:
- 当外部连接通过 VPN 尝试访问服务器(192.168.0.100)时,VPN 网关正确地将请求发送到服务器
- 但是服务器需要回应这些请求,它会查找路由表决定如何发送响应包
- 由于 Docker 网络接口声明它负责 192.168.96.0/20 网段(包含了 VPN 的 192.168.100.0/24 网段)
响应包路由错误:
- 服务器会尝试通过 Docker 网络接口而不是 VPN 接口发送响应数据包
- 这些响应数据包被错误地路由到了 Docker 的网络空间,而不是返回到 VPN 客户端
- 结果是:连接请求可以到达服务器,但响应永远无法返回到发起请求的客户端
网络连接的双向性:
- 建立网络连接需要双向通信成功
- 即使入站连接可以到达目标,如果出站响应无法返回,连接仍然会失败
- 这就是为什么看起来”服务器不能连通”的原因
这种情况类似于网络中的”非对称路由”问题,即数据进入和离开使用不同的路径,但在此情况下,离开的路径实际上是无效的。
解决方案
临时解决
- 执行
docker compose down关闭容器和网络
长期解决
- 在
docker-compose.yml中明确指定网络配置:
1 | networks: |
- 修改 Docker 守护进程默认设置,编辑
/etc/docker/daemon.json:
1 | { |
Docker 守护进程网络配置详解
daemon.json是 Docker 守护进程的主要配置文件,通过修改它可以改变 Docker 的全局行为。上述配置中:
default-address-pools: 定义 Docker 在创建新网络时使用的 IP 地址池
base:
10.10.0.0/16- 指定 Docker 网络使用的基础 IP 地址段- 这里选择 10.10.0.0/16 是因为它是私有地址空间,且通常与企业内部的网络不冲突
- 也可以使用 172.17.0.0/16 或其他私有网段,只要不与现有网络重叠
size:
24- 定义每个 Docker 网络分配的子网大小- 值 24 意味着每个 Docker 网络会获得一个/24 子网(有 256 个 IP 地址)
- 较小的 size 值(如 20)会分配更大的子网,较大的值(如 26)会分配更小的子网
- 根据您的需求选择合适的大小:小型项目可以使用/27 或/28,大型项目可能需要/24 或更大
应用配置步骤:
- 创建或编辑文件:
sudo nano /etc/docker/daemon.json - 添加以上配置内容
- 保存并关闭文件
- 重启 Docker 守护进程:
sudo systemctl restart docker
为什么这能解决问题:
- 通过明确指定 Docker 使用 10.10.0.0/16 网段,避免了与 VPN 使用的 192.168.100.0/24 网段冲突
- 当 Docker 需要创建新网络时,会从这个指定的地址池中分配 IP 段
- 由于使用了完全不同的网段,不会与现有网络路由产生冲突
注意事项:
- 修改此配置会影响所有新创建的 Docker 网络,已存在的网络不受影响
- 重启 Docker 后,可能需要重新创建已有的容器和网络
- 在选择地址段时,确保与整个企业网络规划协调,避免创建新的冲突
总结
这次事件揭示了 Docker 网络自动配置可能带来的潜在问题。在使用 Docker 的生产或测试环境中,应当注意网络规划,避免 IP 地址段冲突,特别是当环境中已有复杂网络设置(如 VPN)时。明确指定 Docker 网络配置是避免此类问题的最佳实践。

