无法实现物理Linux服务器与另一物理服务器上Docker容器的双向IP转发
无法实现物理Linux服务器与另一物理服务器上Docker容器的双向IP转发
场景与拓扑
我有三台服务器:
- 物理服务器A、B:处于同一物理子网
- 虚拟服务器C:运行在B上的WireGuard Docker容器,通过bridge网络驱动连接到B
网络参数明细
| 设备 | 网卡/网络 | IP地址 |
|---|---|---|
| 服务器A | eth1 | 10.0.0.2 |
| 服务器B | eth1 br-XXX(Docker网桥) | 10.0.0.1 10.10.10.1 |
| 服务器C | wg0 eth0 | 10.0.1.1 10.10.10.2 |
子网划分:
- 10.0.0.0/24:A和B的物理子网
- 10.10.10.0/16:B的Docker网桥子网
- 10.0.1.0/24:WireGuard容器C的专属子网
目标
通过服务器B做路由器,不使用NAT的前提下实现双向连通:
- 服务器A(10.0.0.2)能ping通服务器C(10.0.1.1)
- 服务器C(10.0.1.1)能ping通服务器A(10.0.0.2)
当前问题与已做配置
- 现状:B可以ping通A和C,C能ping通B,但A、C之间无法互相ping通,tcpdump甚至抓不到ICMP包
- 已完成的配置:
- 所有设备防火墙允许10.0.0.0/24、10.0.1.0/24的所有ICMP/TCP/UDP流量,以及全量出站流量
- 服务器A已添加路由:
10.0.1.0/24 via 10.0.0.1 dev eth1 - 所有服务器已开启IPv4转发(
sysctl net.ipv4.ip_forward=1)
排查与解决方案
从你的情况来看,核心问题大概率出在Docker网桥的默认转发限制和容器C的回程路由缺失上,我帮你梳理下分步解决步骤:
1. 给容器C添加回程路由
容器C目前只知晓自己的WireGuard子网和Docker网桥子网,完全不知道10.0.0.0/24物理子网的存在,所以收到A的ping请求后,根本不知道该把回复发给谁。你需要在C内添加一条路由:
# 直接在容器C中执行 ip route add 10.0.0.0/24 via 10.10.10.1 dev eth0
如果是用Docker Compose部署,想要让这条路由持久化,修改docker-compose.yml即可:
services: wireguard: # 你的原有配置(镜像、端口等) cap_add: - NET_ADMIN # 必须添加该权限才能修改路由 command: sh -c "ip route add 10.0.0.0/24 via 10.10.10.1 dev eth0 && wg-quick up wg0"
2. 放开Docker网桥的iptables转发限制
Docker默认会给bridge网络添加iptables规则拦截跨网流量,就算你开启了系统的IPv4转发,也可能被Docker的规则拦住。先在B上查看Docker的USER链规则:
iptables -L DOCKER-USER -n
如果看不到允许10.0.0.0/24与10.10.10.0/16之间转发的规则,手动添加:
# 允许物理子网到Docker网桥的流量 iptables -A DOCKER-USER -s 10.0.0.0/24 -d 10.10.10.0/16 -j ACCEPT # 允许Docker网桥到物理子网的流量 iptables -A DOCKER-USER -s 10.10.10.0/16 -d 10.0.0.0/24 -j ACCEPT # 保存规则避免重启失效(不同系统命令有差异) # Debian/Ubuntu 用这条 netfilter-persistent save # RHEL/CentOS 用这条 iptables-save > /etc/sysconfig/iptables
3. 确认服务器B的路由表
虽然B能ping通两边,但还是要确认它的路由表知晓10.0.1.0/24子网的存在。在B上执行:
ip route show
应该能看到类似10.0.1.0/24 via 10.10.10.2 dev br-XXX的路由(br-XXX是你的Docker网桥名称)。如果没有,手动添加:
ip route add 10.0.1.0/24 via 10.10.10.2 dev br-XXX
4. 抓包验证流量走向
完成以上配置后,你可以在三个节点同时开启tcpdump抓ICMP包,定位流量卡滞的环节:
- 在A上:
tcpdump -i eth1 icmp - 在B上:开两个终端,分别执行
tcpdump -i eth1 icmp和tcpdump -i br-XXX icmp - 在C上:开两个终端,分别执行
tcpdump -i eth0 icmp和tcpdump -i wg0 icmp
然后从A ping C,正常流程应该是:
- A发送请求到B的10.0.0.1
- B转发请求到C的10.10.10.2
- C收到后,将回复发给B的10.10.10.1
- B再转发回复到A的10.0.0.2
哪一步没有流量,就针对性排查该节点的防火墙或路由配置即可。
备注:内容来源于stack exchange,提问作者SepSol
相关产品推荐
相关产品推荐

