![使用不同的物理网络接口和默认网关从 docker 容器进行路由](https://linux22.com/image/659668/%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E7%89%A9%E7%90%86%E7%BD%91%E7%BB%9C%E6%8E%A5%E5%8F%A3%E5%92%8C%E9%BB%98%E8%AE%A4%E7%BD%91%E5%85%B3%E4%BB%8E%20docker%20%E5%AE%B9%E5%99%A8%E8%BF%9B%E8%A1%8C%E8%B7%AF%E7%94%B1.png)
背景信息
我有一台运行 Docker 的带有两个网络接口的服务器。Docker 与某些虚拟化工具一样,会创建一个名为 的 Linux 桥接接口docker0
。此接口默认配置为 IP,172.17.42.1
所有 Docker 容器都以此接口作为网关进行通信,并分配同一/16
范围内的 IP 地址。据我了解,所有往返于容器的网络流量都会经过 NAT,因此出站流量似乎来自172.17.42.1
,而入站流量则发送到172.17.42.1
。
我的设置如下:
+------------+ /
| | |
+-------------+ Gateway 1 +-------
| | 10.1.1.1 | /
+------+-------+ +------------+ |
| eth0 | /
| 10.1.1.2 | |
| | |
| DOCKER HOST | |
| | | Internet
| docker0 | |
| (bridge) | |
| 172.17.42.1 | |
| | |
| eth1 | |
| 192.168.1.2 | \
+------+-------+ +------------+ |
| | | \
+-------------+ Gateway 2 +-------
| 192.168.1.1| |
+------------+
问题
我想将来自/到任何 Docker 容器的所有流量从第二个eth1
192.168.1.2
接口路由到默认网关192.168.1.1
,同时让来自/到主机的所有流量从eth0
10.1.1.2
接口流出到默认网关10.1.1.1
。到目前为止,我尝试了各种各样的方法都无济于事,但我认为最接近正确的方法是使用 iproute2,如下所示:
# Create a new routing table just for docker
echo "1 docker" >> /etc/iproute2/rt_tables
# Add a rule stating any traffic from the docker0 bridge interface should use
# the newly added docker routing table
ip rule add from 172.17.42.1 table docker
# Add a route to the newly added docker routing table that dictates all traffic
# go out the 192.168.1.2 interface on eth1
ip route add default via 192.168.1.2 dev eth1 table docker
# Flush the route cache
ip route flush cache
# Restart the Docker daemon so it uses the correct network settings
# Note, I do this as I found Docker containers often won't be able
# to connect out if any changes to the network are made while it's
# running
/etc/init.d/docker restart
当我启动一个容器后,我根本无法从中 ping 出。我不确定桥接接口是否以与物理接口相同的方式处理这种路由,我只想进行健全性检查以及有关如何完成这个看似简单的任务的任何提示。
答案1
我和一位朋友遇到了同样的问题,我们希望让 Docker 支持多个网络接口来处理请求。我们专门使用 AWS EC2 服务,同时还连接/配置/启动其他接口。在这种情况下项目,这里有比您所需要的更多的内容,因此我将尝试仅在此处包含您需要的内容。
首先,我们创建一个单独的路由表eth1
:
ip route add default via 192.168.1.2 dev eth1 table 1001
接下来我们配置 mangle 表来设置一些来自的连接标记eth1
:
iptables -t mangle -A PREROUTING -i eth1 -j MARK --set-xmark 0x1001/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff
最后,我们为所有 s 添加此规则fwmark
以使用我们创建的新表。
ip rule add from all fwmark 0x1001 lookup 1001
以下iptables
命令将恢复连接标记,然后允许路由规则使用正确的路由表。
iptables -w -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff
eth1
我相信这就是我们更复杂的例子所需要的全部内容,其中(就像我说的)我们的项目是在启动时连接/配置/启动界面。
现在,这个例子不会阻止从eth0
服务请求到的连接,docker0
但我相信你可以添加一个路由规则来防止这种情况发生。
答案2
您可能还需要更多地了解 iptables 设置。Docker 将来自容器子网(例如 172.17.0.0/16)的所有流量伪装为 0.0.0.0。如果您运行iptables -L -n -t nat
,您可以看到 nat 表下的 POSTROUTING 链,它执行此操作 -
链 POSTROUTING(策略接受) 目标 保护 优化 源 目标 MASQUERADE 全部 -- 172.17.0.0/16 0.0.0.0/0
现在,您可以删除此规则并将其替换为一条规则,该规则将所有来自容器子网的流量伪装成第二个接口的 IP - 192.168.1.2,因为这是您想要的。删除规则将是,假设它是 POSTROUTING 链下的第一个规则 -
iptables -t nat -D POSTROUTING 1
然后添加此自定义规则 -
iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --到源 192.168.1.2
答案3
伪装不是来自 172.17.42.1,而是
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
这意味着这条规则无法正常发挥作用。
ip rule add from 172.17.42.1 table docker
尝试一下
ip rule add from 172.17.0.0/16 table docker