Docker 路由模式(No NAT)内网互通配置文档

作者:Administrator 发布时间: 2026-02-12 阅读量:1 评论数:0

1. 方案简介

本方案采用 路由模式 (Routed Mode) 替代 Docker 默认的 NAT 模式。

  • 原理:宿主机作为路由器,直接转发物理网络与容器网络之间的流量。

  • 优势

    • 真实 IP:容器拥有独立的局域网 IP,便于管理和监控。

    • 高性能:去除了 NAT 转换损耗,网络吞吐更高。

    • 双向互通:局域网内的其他机器可以直接访问容器 IP。

2. 网络规划示例

假设物理局域网网段为 192.168.6.0/24,规划给 Docker 使用的网段为 172.30.1.0/24

节点

角色

IP 地址

说明

物理交换机/路由器

核心网关

192.168.6.1

需配置静态路由

宿主机 (Linux)

容器宿主

192.168.6.157

需开启转发

Docker 容器

业务节点

172.30.1.x

网关指向 172.30.1.1


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 ACCEPT

4. 自动化守护脚本(生产环境推荐)

由于 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

部署建议

  1. 赋予执行权限:chmod +x /usr/local/bin/fix_docker_route.sh

  2. 加入 Crontab 计划任务(每分钟检查一次,确保网络高可用):

    * * * * * root /usr/local/bin/fix_docker_route.sh >> /var/log/docker_route_fix.log 2>&1

5. 验证测试

完成上述配置后,进行以下测试:

  1. 启动测试容器

    docker run -d --name test-app --network routed-net --ip 172.30.1.2 nginx
  2. 连通性检查

    • 从局域网其他电脑 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,则通;否则不通。

评论