使用容器化的软件搭建多节点集群时,不可避免要解决容器之间的网络通信问题,Docker容器默认的网络设置只允许同一宿主机上的容器间通信,想要让两个不同主机上的容器能够通信,通常有以下几种做法:
本文尝试使用自定义网桥,仅通过主机静态路由,使不同主机的容器网段互通。
两台宿主机:
两个宿主机上的Docker容器使用不同网段避免了IP冲突。
在宿主机定义路由规则:
数据包在两个容器间的传递过程如下:
主机A上容器数据包首先发给docker0,然后通过查找主机A上的路由得知需要将数据包发给主机B,数据包到达主机B后再转发给主机B的docker0,最后将数据包转到主机B的容器中。
在每台主机上创建不重叠的子网:
# 在主机A上创建网络
docker network create --subnet 10.0.1.0/24 netA
# 在主机B上创建网络
docker network create --subnet 10.0.2.0/24 netB
在两台宿主机上启用内核IP转发:
sysctl -w net.ipv4.ip_forward=1
# 永久生效(可选)
echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.conf
在主机A上:
指向主机B的容器网段(10.0.2.0/24)的流量发送到主机B的IP:
ip route add 10.0.2.0/24 via 192.168.0.2
在主机B上:
指向主机A的容器网段(10.0.1.0/24)的流量发送到主机A的IP:
ip route add 10.0.1.0/24 via 192.168.0.1
允许宿主机间转发流量(以iptables为例):
# 在主机A和主机B上执行
# 允许宿主机(通过物理网卡 eth0)与 Docker 容器网络(通过虚拟网桥 docker0)之间的双向流量转发
iptables -A FORWARD -i eth0 -o docker0 -j ACCEPT
iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
# 启用SNAT(可选,解决非对称路由)
iptables -t nat -A POSTROUTING -s 10.0.1.0/24 ! -d 10.0.1.0/24 -j MASQUERADE
注意:
- 替换 eth0 为主机实际网卡名(如 ens33)。
- 替换 docker0 为创建netA/netB容器子网网卡名(如 br-e981899c7a90)。
- 若使用 firewalld/ufw,需放行容器网段和宿主机间通信。
docker run --rm -it --net netA ubuntu:24.04 /bin/bash
docker run --rm -it --net netB ubuntu:24.04 /bin/bash
ping 10.0.1.2
ip route show # 确认静态路由存在
iptables -L -v -n # 查看FORWARD链是否放行
tcpdump -i eth0 host 192.168.0.1 # 在主机A抓包观察流量