![如何更新 Linux 主机 iptables 规则以重定向 Docker 容器内的流量?](https://linux22.com/image/169151/%E5%A6%82%E4%BD%95%E6%9B%B4%E6%96%B0%20Linux%20%E4%B8%BB%E6%9C%BA%20iptables%20%E8%A7%84%E5%88%99%E4%BB%A5%E9%87%8D%E5%AE%9A%E5%90%91%20Docker%20%E5%AE%B9%E5%99%A8%E5%86%85%E7%9A%84%E6%B5%81%E9%87%8F%EF%BC%9F.png)
我想将 docker 容器内的出站流量重新映射到不同的端口。例如:我想curl 1.2.3.4:8080
从容器内实际向 发出请求curl 1.2.3.4:8181
。 (这类似于 kube-proxy 对 kubernetes 所做的事情)。
我知道在 docker 容器中我可以运行:
iptables -t nat -A OUTPUT -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to-destination 1.2.3.4:8181
然后请求将按预期运行。但是,我只想编辑主机上的 iptables 规则以获得相同的功能。
我有一个 id 的 docker 网络8e8799c36e69
,如果我iptables-save | grep 8e8799c36e69
在主机上运行,我会得到以下规则:
-A POSTROUTING -s 172.18.0.0/16 ! -o br-8e8799c36e69 -j MASQUERADE
-A DOCKER -i br-8e8799c36e69 -j RETURN
-A FORWARD -o br-8e8799c36e69 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-8e8799c36e69 -j DOCKER
-A FORWARD -i br-8e8799c36e69 ! -o br-8e8799c36e69 -j ACCEPT
-A FORWARD -i br-8e8799c36e69 -o br-8e8799c36e69 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-8e8799c36e69 ! -o br-8e8799c36e69 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-2 -o br-8e8799c36e69 -j DROP
是否可以加入这些规则,以便我可以在该网络内设置端口重写? (这个事件是正确的做法吗?)。
也许只是这样的事情?
iptables -t nat -I OUTPUT -o br-8e8799c36ec9 --src 0/0 --dst 1.2.3.4 -p tcp --dport 8080 -j REDIRECT --to-ports 8181
或者也许我不需要 docker 桥接网络,并且我可以以某种方式过滤来自容器内的流量?
编辑:
当我启动 docker 容器时,它会创建以下规则:
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8080
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT
容器172.17.0.2
在我的机器上有 ip addr。所以我添加了这条规则:
sudo iptables -t nat -A OUTPUT -s 172.17.0.2/32 -p tcp -d 172.217.3.110 --dport 8080 -j DNAT --to-destination 172.217.3.110:80
尝试向172.217.3.110:8080
request发送测试请求172.217.3.110:80
,但似乎不起作用。
编辑2:
如果我尝试重写本地侦听服务的端口,我可以使用以下命令:
LOCAL_IP=192.168.86.30
REQUESTED_PORT=80
DESTINATION_PORT=8080
CONTAINER_IP=172.17.0.2
sudo iptables -t nat -A OUTPUT -p tcp -d $LOCAL_IP --dport $REQUESTED_PORT -j DNAT --to-destination :$DESTINATIO_PORT
sudo iptables -t nat -I PREROUTING -s $CONTAINER_IP -d $LOCAL_IP -p tcp --dport $REQUESTED_PORT -j REDIRECT --to-ports $DESTINATION_PORT
这似乎只适用于本地 ip
编辑3: kube-proxy 来源有一些关于他们的方法和各种陷阱的更多信息:
https://github.com/kubernetes/kubernetes/blob/84dc704/pkg/proxy/userspace/proxier.go#L1133-L1165
答案1
好吧,想通了。
如果我想将流量从192.168.86.30:80
重定向到192.168.86.30:8084
具有 IP 地址的容器172.17.0.2
,那么您可以添加以下规则:
sudo iptables -t nat -A PREROUTING --protocol tcp --destination 192.168.86.30 \
--dport 80 --source 172.17.0.2 \
--jump DNAT --to-destination 192.168.86.30:8084
这似乎也适用于公共外部 IP 地址。
REDIRECT
似乎不起作用,因为[来源]:
它通过将目标 IP 更改为传入接口的主地址(本地生成的数据包映射到 127.0.0.1 地址),将数据包重定向到机器本身。
仍然不完全确定发生了什么,但我认为这就是为什么 REDIRECT 可以处理本地服务的某些内容(尤其是在 0.0.0.0 上侦听的任何内容),但不能处理外部 ip。