1. 方案简介
本方案采用 路由模式 (Routed Mode) 替代 Docker 默认的 NAT 模式。
原理:宿主机作为路由器,直接转发物理网络与容器网络之间的流量。
优势:
真实 IP:容器拥有独立的局域网 IP,便于管理和监控。
高性能:去除了 NAT 转换损耗,网络吞吐更高。
双向互通:局域网内的其他机器可以直接访问容器 IP。
2. 网络规划示例
假设物理局域网网段为 192.168.6.0/24,规划给 Docker 使用的网段为 172.30.1.0/24。
3. 配置步骤
第一步:物理网络侧配置(静态路由)
在局域网的核心交换机或上级路由器上添加一条静态路由,指明容器网段的去向。
目标网段:
172.30.1.0/24(掩码 255.255.255.0)下一跳 (Gateway):
192.168.6.157(宿主机的物理 IP)
作用:确保局域网内的其他机器发往
172.30.1.x的数据包能正确到达宿主机。
第二步:Docker 网络创建
在宿主机上创建一个关闭 NAT (IP Masquerade) 的自定义网桥。
docker network create \
--driver bridge \
--subnet=172.30.1.0/24 \
--gateway=172.30.1.1 \
--opt "com.docker.network.bridge.name=br-routed" \
--opt "com.docker.network.bridge.enable_ip_masquerade=false" \
routed-net关键参数:
enable_ip_masquerade=false禁止了 SNAT,从而保留了容器的真实源 IP。
第三步:宿主机内核转发开启
宿主机必须开启 IP Forwarding 功能,才能在物理网卡和 Docker 网桥之间转发数据包。
临时生效:
sysctl -w net.ipv4.ip_forward=1永久生效:
编辑 /etc/sysctl.conf,添加或修改:
net.ipv4.ip_forward = 1然后执行 sysctl -p 生效。
第四步:Iptables 防火墙修正(核心关键)
Docker 在关闭 NAT 模式下,为了防止 IP 欺骗,默认会在 raw 表的 PREROUTING 链中添加一条 DROP 规则,拦截所有非 Docker 网桥进入的目标为容器网段的包。
现象:外部机器 Ping 容器 IP 时,包到达宿主机网卡后被直接丢弃。
修复命令(在 Docker 的 DROP 规则之前插入一条 ACCEPT 规则):
# 将允许规则插入到 raw 表 PREROUTING 链的第一位
iptables -t raw -I PREROUTING 1 -d 172.30.1.0/24 -j ACCEPT4. 自动化守护脚本(生产环境推荐)
由于 Docker 服务重启或网络重载可能会重新生成 iptables 规则,导致我们手动添加的规则位置被挤后(从而失效)。建议使用以下脚本进行自动维护。
脚本路径:/usr/local/bin/fix_docker_route.sh
#!/bin/bash
# ================= 配置区域 =================
# Docker 自定义网段
TARGET_NET="172.30.1.0/24"
# ===========================================
# 1. 确保内核转发开启
sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1
# 2. 修复 iptables raw 表规则
# Docker 会自动添加 DROP 规则拦截外部流量,我们需要在它前面加 ACCEPT
TABLE="raw"
CHAIN="PREROUTING"
# 定义规则特征
RULE_SPEC="-d ${TARGET_NET} -j ACCEPT"
# 检查 ACCEPT 规则是否在第一位
# 获取第一条规则的信息,判断是否包含我们的目标网段
FIRST_RULE=$(iptables -t ${TABLE} -nL ${CHAIN} --line-numbers | grep "^1 " | grep "${TARGET_NET}")
if [ -z "${FIRST_RULE}" ]; then
echo "$(date) - Fixing iptables raw chain rules..."
# 删除可能存在的旧规则(防止重复或位置不对)
iptables -t ${TABLE} -D ${CHAIN} ${RULE_SPEC} 2>/dev/null
# 强制插入到第一位 (Priority 1)
iptables -t ${TABLE} -I ${CHAIN} 1 ${RULE_SPEC}
echo "$(date) - Iptables rule fixed."
else
echo "$(date) - Iptables rule is correct."
fi部署建议:
赋予执行权限:
chmod +x /usr/local/bin/fix_docker_route.sh加入 Crontab 计划任务(每分钟检查一次,确保网络高可用):
* * * * * root /usr/local/bin/fix_docker_route.sh >> /var/log/docker_route_fix.log 2>&1
5. 验证测试
完成上述配置后,进行以下测试:
启动测试容器:
docker run -d --name test-app --network routed-net --ip 172.30.1.2 nginx连通性检查:
从局域网其他电脑 Ping 容器:
ping 172.30.1.2预期结果:通
从容器 Ping 外部网络:
docker exec -it test-app ping 192.168.6.1预期结果:通
从容器 Ping 公网(如 8.8.8.8):
预期结果:取决于上级路由器是否配置了对
172.30.1.0/24网段的 NAT (SNAT)。如果上级路由做了 NAT,则通;否则不通。