Wie aktualisiere ich die Iptables-Regeln eines Linux-Hosts, um den Datenverkehr innerhalb eines Docker-Containers umzuleiten?

Wie aktualisiere ich die Iptables-Regeln eines Linux-Hosts, um den Datenverkehr innerhalb eines Docker-Containers umzuleiten?

Ich möchte ausgehenden Datenverkehr innerhalb eines Docker-Containers auf einen anderen Port umleiten. Beispiel: Ich möchte curl 1.2.3.4:8080aus dem Container heraus und die Anforderung tatsächlich an senden curl 1.2.3.4:8181. (Dies ist ähnlich dem, was kube-proxy für Kubernetes macht.)

Ich verstehe, dass ich in einem Docker-Container Folgendes ausführen kann:

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

Und dann verhalten sich die Anfragen wie gewünscht. Ich möchte jedoch nur die iptables-Regeln auf dem Host bearbeiten, um die gleiche Funktionalität zu erhalten.

Ich habe ein Docker-Netzwerk mit der ID 8e8799c36e69. Wenn ich es iptables-save | grep 8e8799c36e69auf dem Host ausführe, erhalte ich die folgenden Regeln:

-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

Ist es möglich, diese Regeln anzuzapfen, sodass ich meine Port-Neuschreibung nur innerhalb dieses Netzwerks einrichten kann? (Ist dieses Ereignis der richtige Ansatz?).

Vielleicht einfach so etwas?

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

Oder brauche ich das Docker-Bridge-Netzwerk vielleicht nicht und kann den Datenverkehr, der aus dem Container kommt, irgendwie filtern?

bearbeiten:

Wenn ich einen Docker-Container starte, werden diese Regeln erstellt:

-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

Der Container hat eine IP-Adresse 172.17.0.2auf meinem Rechner. Daher habe ich diese Regel hinzugefügt:

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

Ich habe versucht, eine Testanfrage zu erhalten 172.217.3.110:8080, 172.217.3.110:80aber es scheint nicht zu funktionieren.

Bearbeitung 2:

Wenn ich versuche, einen Port für einen lokal lauschenden Dienst neu zu schreiben, funktioniert es folgendermaßen:

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

das scheint nur mit lokalen IPs zu funktionieren

Bearbeitung 3: Die Kube-Proxy-Quelle enthält weitere Informationen zu ihrem Ansatz und verschiedenen Fallstricken:

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

Antwort1

OK, habe es herausgefunden.

192.168.86.30:80Wenn ich den Datenverkehr von zu 192.168.86.30:8084einem Container mit einer IP-Adresse umleiten möchte, 172.17.0.2können Sie die folgende Regel hinzufügen:

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

Dies scheint auch mit öffentlichen externen IP-Adressen zu funktionieren.

REDIRECTscheint nicht zu funktionieren, weil[Quelle]:

Es leitet das Paket an die Maschine selbst um, indem es die Ziel-IP in die primäre Adresse der eingehenden Schnittstelle ändert (lokal generierte Pakete werden der Adresse 127.0.0.1 zugeordnet).

Ich bin mir immer noch nicht ganz sicher, was da los war, aber ich glaube, das ist der Grund, warum REDIRECT bei einigen lokal bereitgestellten Dingen funktionierte (insbesondere bei allem, was auf 0.0.0.0 lauschte), aber nicht bei externen IPs.

verwandte Informationen