docker 容器中基于端口的路由
Port based routing in docker container
我有一个 docker 应用程序容器(node:latest
图像),它有两个网络接口:
- eth1: 这是默认接口,是来自服务的所有容器之间的桥接网络。 (由
pipework
管理,但我无法更改该级别的任何内容)
- eth0: 这是一个常规的
docker0
接口,可以访问除 eth1
. 以外的任何地方
这里是默认路由 table:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.25.88.254 0.0.0.0 UG 0 0 0 eth1
10.25.88.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
如您所见,有必要将 eth1
作为默认界面,但这给我带来了一个问题:我的应用程序需要 ssh
访问其他一些无法通过 [= 访问的远程服务器18=] 但 eth0
具有访问权限。所以我需要更改此请求的路由。我的第一个解决方案是:
route add -net 10.20.33.0/24 gw 172.17.42.1
这种方法工作正常,我将可以访问 10.20.33.0/24
范围内的那些地址。但它会阻止从这些主机访问应用程序本身。该应用程序在端口 80 上提供服务,添加此路由后,10.20.33.0/24
范围内的主机对它的所有请求都将失败。
所以我认为该路由是全球性的,并且会影响对该 IP 范围的所有 input/output 请求。我搜索了一种方法来在整个 Whosebug 中路由输出 ssh 请求,到目前为止,这就是我所拥有的:
# Initialize route table
echo 1 p.ssh > /etc/iproute2/rt_tables
ip route add table p.ssh default via 172.17.42.1
# Mark Packet with matching D.Port
iptables -A PREROUTING -t mangle -p tcp --dport 22 -j MARK --set-mark 1
iptables -A POSTROUTING -t nat -o eth0 -p tcp --dport 22 -j SNAT --to 172.17.42.1
#IP Route
ip rule add fwmark 1 table p.ssh
ip route flush cache
#IP Stack
#This is the missing part from the guide
echo 1 > /proc/sys/net/ipv4/ip_forward
for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done
echo 0 > /proc/sys/net/ipv4/route/flush
但它不起作用。我试图通过 iptables
记录标记的包,所以也许我可以在这个过程中发现任何问题,但是容器内的 syslog
不是 运行,所以我安装了它 apt-get install rsyslog
并添加了这条规则:
iptables -A PREROUTING -t mangle -p tcp --dport 22 -j LOG --log-level 4 --log-prefix "fwmark 1: "
但它也没有记录任何内容。
几天后我解决了这个问题。我按如下方式使用 tcpdump
来确定流量是否通过 eth0
接口路由:
tcpdump -i eth0 port ssh
结果发现第一个问题来自iptables
标记命令。因此,我没有在 PREROUTING
链上标记请求,而是在 OUTPUT
链上标记它们,如下所示:
iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
现在我可以在 eth0
上看到 ssh 请求,但我仍然无法连接。事实证明,此请求需要伪装才能正常运行:
iptables --table nat --append POSTROUTING -o eth0 -p tcp --dport 22 -j MASQUERADE
最终脚本如下:
REMOTE_HOSTS=10.20.33.0/24
HOSTS_ADDR=172.17.42.1
# Add table
echo 1 p.ssh >> /etc/iproute2/rt_tables
# Add route
ip rule add fwmark 1 table p.ssh
ip route add $REMOTE_HOSTS via $HOSTS_ADDR dev eth0 table p.ssh
# Sets mark correctly
iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
iptables --table nat --append POSTROUTING -o eth0 -p tcp --dport 22 -j MASQUERADE
#IP Stack
echo 1 > /proc/sys/net/ipv4/ip_forward # Default in debian/ubuntu
for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done
我有一个 docker 应用程序容器(node:latest
图像),它有两个网络接口:
- eth1: 这是默认接口,是来自服务的所有容器之间的桥接网络。 (由
pipework
管理,但我无法更改该级别的任何内容) - eth0: 这是一个常规的
docker0
接口,可以访问除eth1
. 以外的任何地方
这里是默认路由 table:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.25.88.254 0.0.0.0 UG 0 0 0 eth1
10.25.88.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
如您所见,有必要将 eth1
作为默认界面,但这给我带来了一个问题:我的应用程序需要 ssh
访问其他一些无法通过 [= 访问的远程服务器18=] 但 eth0
具有访问权限。所以我需要更改此请求的路由。我的第一个解决方案是:
route add -net 10.20.33.0/24 gw 172.17.42.1
这种方法工作正常,我将可以访问 10.20.33.0/24
范围内的那些地址。但它会阻止从这些主机访问应用程序本身。该应用程序在端口 80 上提供服务,添加此路由后,10.20.33.0/24
范围内的主机对它的所有请求都将失败。
所以我认为该路由是全球性的,并且会影响对该 IP 范围的所有 input/output 请求。我搜索了一种方法来在整个 Whosebug 中路由输出 ssh 请求,到目前为止,这就是我所拥有的:
# Initialize route table
echo 1 p.ssh > /etc/iproute2/rt_tables
ip route add table p.ssh default via 172.17.42.1
# Mark Packet with matching D.Port
iptables -A PREROUTING -t mangle -p tcp --dport 22 -j MARK --set-mark 1
iptables -A POSTROUTING -t nat -o eth0 -p tcp --dport 22 -j SNAT --to 172.17.42.1
#IP Route
ip rule add fwmark 1 table p.ssh
ip route flush cache
#IP Stack
#This is the missing part from the guide
echo 1 > /proc/sys/net/ipv4/ip_forward
for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done
echo 0 > /proc/sys/net/ipv4/route/flush
但它不起作用。我试图通过 iptables
记录标记的包,所以也许我可以在这个过程中发现任何问题,但是容器内的 syslog
不是 运行,所以我安装了它 apt-get install rsyslog
并添加了这条规则:
iptables -A PREROUTING -t mangle -p tcp --dport 22 -j LOG --log-level 4 --log-prefix "fwmark 1: "
但它也没有记录任何内容。
几天后我解决了这个问题。我按如下方式使用 tcpdump
来确定流量是否通过 eth0
接口路由:
tcpdump -i eth0 port ssh
结果发现第一个问题来自iptables
标记命令。因此,我没有在 PREROUTING
链上标记请求,而是在 OUTPUT
链上标记它们,如下所示:
iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
现在我可以在 eth0
上看到 ssh 请求,但我仍然无法连接。事实证明,此请求需要伪装才能正常运行:
iptables --table nat --append POSTROUTING -o eth0 -p tcp --dport 22 -j MASQUERADE
最终脚本如下:
REMOTE_HOSTS=10.20.33.0/24
HOSTS_ADDR=172.17.42.1
# Add table
echo 1 p.ssh >> /etc/iproute2/rt_tables
# Add route
ip rule add fwmark 1 table p.ssh
ip route add $REMOTE_HOSTS via $HOSTS_ADDR dev eth0 table p.ssh
# Sets mark correctly
iptables -t mangle -A OUTPUT -p tcp --dport 22 -j MARK --set-mark 1
iptables --table nat --append POSTROUTING -o eth0 -p tcp --dport 22 -j MASQUERADE
#IP Stack
echo 1 > /proc/sys/net/ipv4/ip_forward # Default in debian/ubuntu
for f in /proc/sys/net/ipv4/conf/*/rp_filter ; do echo 0 > $f ; done