如何更新 Linux 主机 iptables 规则以重定向 Docker 容器内的流量?

如何更新 Linux 主机 iptables 规则以重定向 Docker 容器内的流量?

我想将 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:8080request发送测试请求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

https://github.com/kubernetes/kubernetes/blob/84dc7046797aad80f258b6740a98e79199c8bb4d/pkg/proxy/userspace/proxier.go#L1180-L1200

答案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。

相关内容