Como atualizo as regras de iptables do host Linux para redirecionar o tráfego dentro de um contêiner docker?

Como atualizo as regras de iptables do host Linux para redirecionar o tráfego dentro de um contêiner docker?

Gostaria de remapear o tráfego de saída de um contêiner docker para uma porta diferente. Por exemplo: eu gostaria de curl 1.2.3.4:8080entrar no contêiner e fazer com que a solicitação fosse realmente feita para curl 1.2.3.4:8181. (isso é semelhante ao que o kube-proxy faz para o kubernetes).

Entendo que dentro de um contêiner docker posso executar:

iptables -t nat -A OUTPUT -p tcp -d 1.2.3.4 --dport 8080 -j DNAT --to-destination 1.2.3.4:8181

E então as solicitações se comportarão conforme desejado. No entanto, gostaria de editar apenas as regras do iptables no host para obter a mesma funcionalidade.

Eu tenho uma rede docker com id 8e8799c36e69, se eu rodar iptables-save | grep 8e8799c36e69no host recebo as seguintes regras:

-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

É possível conectar-se a essas regras para que eu possa configurar minha reescrita de porta apenas dentro dessa rede? (este evento é a abordagem correta?).

Talvez apenas algo assim?

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

Ou talvez eu não precise da rede docker bridge e possa de alguma forma filtrar o tráfego proveniente de dentro do contêiner?

editar:

Quando inicio um contêiner docker, ele cria estas regras:

-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

O contêiner possui endereço IP 172.17.0.2na minha máquina. Então adicionei esta regra:

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

Para tentar obter uma solicitação de teste para 172.217.3.110:8080request 172.217.3.110:80, mas parece não funcionar.

editar 2:

Se estou tentando reescrever uma porta para um serviço que está escutando localmente, consegui trabalhar com isto:

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

isso parece funcionar apenas com ips locais

editar 3: A fonte kube-proxy tem mais algumas informações sobre sua abordagem e várias pegadinhas:

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

Responder1

Ok, descobri.

Se eu quiser redirecionar o tráfego de 192.168.86.30:80para 192.168.86.30:8084um contêiner com um endereço IP 172.17.0.2, você poderá adicionar a seguinte regra:

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

Isso também parece funcionar com endereços IP externos públicos.

REDIRECTnão parece funcionar porque[fonte]:

Ele redireciona o pacote para a própria máquina, alterando o IP de destino para o endereço primário da interface de entrada (os pacotes gerados localmente são mapeados para o endereço 127.0.0.1).

Ainda não tenho certeza do que estava acontecendo, mas acho que é por isso que o REDIRECT estava trabalhando com algumas coisas servidas localmente (especialmente qualquer coisa que escutasse em 0.0.0.0), mas não com ips externos.

informação relacionada