Routing von Docker-Containern mithilfe einer anderen physischen Netzwerkschnittstelle und eines anderen Standardgateways


13

Hintergrundinformation

Ich habe einen Server mit zwei Netzwerkschnittstellen, auf dem Docker ausgeführt wird. Docker erstellt wie einige Virtualisierungstools eine Linux-Bridge-Schnittstelle mit dem Namen docker0. Diese Schnittstelle ist standardmäßig mit einer IP von konfiguriert, 172.17.42.1und alle Docker-Container kommunizieren mit dieser Schnittstelle als Gateway und erhalten IP-Adressen im selben /16Bereich. Soweit ich weiß, wird der gesamte Netzwerkverkehr zu / von Containern über ein NAT abgewickelt, so dass er anscheinend von einem NAT ausgeht 172.17.42.1und an einen eingehenden Datenverkehr gesendet wird 172.17.42.1.

Mein Setup sieht so aus:

                                          +------------+        /
                                          |            |       |
                            +-------------+ Gateway 1  +-------
                            |             | 10.1.1.1   |     /
                     +------+-------+     +------------+    |
                     |     eth0     |                      /
                     |   10.1.1.2   |                      |
                     |              |                      |
                     | DOCKER HOST  |                      |
                     |              |                      | Internet
                     |   docker0    |                      |
                     |   (bridge)   |                      |
                     |  172.17.42.1 |                      |
                     |              |                      |
                     |     eth1     |                      |
                     |  192.168.1.2 |                      \
                     +------+-------+     +------------+    |
                            |             |            |     \
                            +-------------+ Gateway 2  +-------
                                          | 192.168.1.1|       |
                                          +------------+            

Das Problem

Ich möchte den gesamten Datenverkehr von / zu Docker-Containern aus der zweiten eth1 192.168.1.2Schnittstelle an ein Standard-Gateway von leiten 192.168.1.1, während der gesamte Datenverkehr vom / zum Host-Computer über die eth0 10.1.1.2Schnittstelle an ein Standard-Gateway von leiten soll 10.1.1.1. Ich habe eine Reihe von Dingen bisher erfolglos ausprobiert, aber das, was meiner Meinung nach am ehesten zu korrigieren ist, ist, iproute2 wie folgt zu verwenden:

# Create a new routing table just for docker
echo "1 docker" >> /etc/iproute2/rt_tables

# Add a rule stating any traffic from the docker0 bridge interface should use 
# the newly added docker routing table
ip rule add from 172.17.42.1 table docker

# Add a route to the newly added docker routing table that dictates all traffic
# go out the 192.168.1.2 interface on eth1
ip route add default via 192.168.1.2 dev eth1 table docker

# Flush the route cache
ip route flush cache

# Restart the Docker daemon so it uses the correct network settings
# Note, I do this as I found Docker containers often won't be able
# to connect out if any changes to the network are made while it's     
# running
/etc/init.d/docker restart

Wenn ich einen Container aufbringe, kann ich danach gar nicht mehr herauspingen. Ich bin nicht sicher, ob Bridge-Schnittstellen genauso behandelt werden wie physische Schnittstellen für diese Art von Routing. Ich möchte lediglich eine Überprüfung der Integrität sowie Tipps, wie ich diese scheinbar einfache Aufgabe ausführen kann.


Dein Kommentar zum NAT ist nicht richtig. Es ist so eingestellt, dass es auf der Quelladresse 172.17.0.0/16 maskiert wird, wo die Ausgabeschnittstelle nicht docker0 ist. dh -Eine POSTROUTING -s 172.17.0.0/16! -o docker0 -j MASKERADE. Das heißt, wenn das Paket, das von einem Docker-Container stammt, über eth0 oder eth1 beendet wird, übernimmt es diese Schnittstellen-IP-Adresse und nicht die IP 172.17.xx.
Matt

Vielen Dank für Ihren Kommentar. Das würde also meinen Ansatz für das Routing aus einer bestimmten Schnittstelle heraus ändern, richtig? Wissen Sie, wie ich das erreichen könnte? Derzeit scheint Docker nur das Standard-Gateway des Host-Systems zu verwenden, und dies ist nicht das gewünschte Verhalten. Ich möchte, dass Docker alles über eine bestimmte Schnittstelle routet.

Ich bin nicht sicher, warum das, was ich vorgeschlagen habe, nicht funktioniert. Eine andere Möglichkeit könnte die Verwendung von Rohrleitungen sein. github.com/jpetazzo/pipework Auch der Abschnitt für erweiterte Netzwerkfunktionen in der Docker-Hilfe kann hilfreich sein. docs.docker.com/articles/networking
Matt

@Matt Ich danke Ihnen für Ihre Vorschläge dazu. Nach dem, was ich gelesen habe, erfordert Pipework zusätzliche Befehle, nachdem ein Container gestartet wurde, um Zugriff auf das richtige Gateway zu erhalten, was wie eine Sicherheitslücke erscheint. Es wurde ursprünglich entwickelt, um Container über mehrere Hosts hinweg miteinander zu verbinden, was hier wirklich nicht mein Ziel ist. Was die erweiterten Netzwerkdokumente von Docker angeht, werde ich noch einmal einen Blick darauf werfen, aber in dieser Situation war es bisher nicht hilfreich (ich hatte es vor dem Posten hier gelesen). Ich werde einen Link zu diesem Beitrag auf der Docker Github Issues-Seite veröffentlichen und sehen, wie es von dort weitergeht.

Hier ist ein Link zurück zur Github-Ausgabe: github.com/docker/docker/issues/13762

Antworten:


1

Möglicherweise müssen Sie auch mehr über das Setup von iptables nachdenken. Docker maskiert den gesamten Datenverkehr, der aus dem Container-Subnetz stammt, z. B. 172.17.0.0/16, auf 0.0.0.0. Wenn Sie ausführen iptables -L -n -t nat, können Sie die POSTROUTING-Kette unter der entsprechenden Tabelle sehen.

Chain POSTROUTING (Policy ACCEPT)
Zielprotokoll Quellenziel
MASQUERADE all - 172.17.0.0/16 0.0.0.0/0

Jetzt können Sie diese Regel entfernen und durch eine Regel ersetzen, die den gesamten Datenverkehr aus dem Subnetz der Container zur IP - 192.168.1.2 Ihrer zweiten Schnittstelle maskiert, wie Sie es wünschen. Die Löschregel lautet, sofern es sich um die erste Regel in der POSTROUTING-Kette handelt:

iptables -t nat -D POSTROUTING 1

Dann fügen Sie diese benutzerdefinierte Regel hinzu -

iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT - zur Quelle 192.168.1.2

Tatsächlich maskiert es es zur Ausgabeschnittstelle. Dieser Zielteil sagt nur, dass jeglicher Verkehr, der vom Quell-Subnetz zu irgendeinem Ziel stammt, maskiert wird.
Matt

Das hat leider nicht geklappt. Mein kompletter Prozess war zu laufen: ip rule add from 172.17.0.0/16 table docker ip route add default via 192.168.1.2 dev eth1 table docker ip route flush cache iptables -t nat -D POSTROUTING 1 iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j SNAT --to-source 192.168.1.2 /etc/init.d/docker restart. Dann habe ich versucht, einen Ping-out und eine Traceroute aus einem Container zu starten und konnte nichts erreichen.

Ich hatte eine ähnliche Anforderung, Host hat sekundäre IP-Setup, um eine öffentliche IP zu erreichen. Und ich wollte, dass Docker-Container dasselbe tun. Dies funktionierte in diesem Fall: "iptables -t nat -I POSTROUTING 1 -s 172.17.0.0/16 -d PUBIP / 32 -j SNAT -to-source SECONDARYIP"
Ram

1

Ein Freund und ich hatten genau dieses Problem, bei dem wir wollten, dass Docker mehrere Netzwerkschnittstellen unterstützen, die Anfragen bearbeiten. Wir haben speziell mit dem AWS EC2-Service zusammengearbeitet, bei dem wir auch die zusätzlichen Schnittstellen angeschlossen / konfiguriert / aufgerufen haben. In diesem Projekt gibt es mehr als das, was Sie brauchen. Ich werde versuchen, nur das einzubeziehen, was Sie hier brauchen.

Zunächst haben wir eine separate Routentabelle erstellt für eth1:

ip route add default via 192.168.1.2 dev eth1 table 1001

Als nächstes haben wir die Mangeltabelle so konfiguriert, dass einige Verbindungsmarkierungen gesetzt werden, die von kommen eth1:

iptables -t mangle -A PREROUTING -i eth1 -j MARK --set-xmark 0x1001/0xffffffff
iptables -t mangle -A PREROUTING -i eth1 -j CONNMARK --save-mark --nfmask 0xffffffff --ctmask 0xffffffff

Schließlich fügen wir diese Regel hinzu, damit alle fwmarks die neu erstellte Tabelle verwenden können.

ip rule add from all fwmark 0x1001 lookup 1001

Mit dem folgenden iptablesBefehl wird die Verbindungsmarke wiederhergestellt, und die Routing-Regel kann die richtige Routing-Tabelle verwenden.

iptables -w -t mangle -A PREROUTING -i docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff

Ich glaube, dies ist alles, was in unserem komplexeren Beispiel benötigt wird, in dem (wie gesagt) unser Projekt die eth1Schnittstelle beim Booten anhängt / konfiguriert / aufruft .

Jetzt würde dieses Beispiel die Verbindungen nicht davon abhalten eth0, Anfragen zu bearbeiten, docker0aber ich glaube, Sie könnten eine Routing-Regel hinzufügen, um dies zu verhindern.


@stuntmachine einfach mal gespannt ob du das mal ausprobieren konntest? Wenn Sie bereits selbst etwas herausgefunden haben, können Sie dann Ihre Lösung teilen?
Williamsbdev

Hallo @williamsbdev - alter Beitrag und ein langer Schuss, aber denkst du, diese Lösung würde auch für mein Problem bei SO funktionieren? stackoverflow.com/questions/51312310/…
Jolly Roger

2
Jolly Roger - Ich glaube, dies wird Ihr Problem lösen. Ich wurde kürzlich von einem anderen Team nach diesem Blog-Beitrag gefragt (im Wesentlichen die gleiche Lösung wie hier) und sie sagten, dass es großartig funktioniert hat. williamsbdev.com/posts/docker-connection-marking
williamsbdev

0

Die Maskerade ist nicht vom 172.17.42.1 sondern eher

 -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE

Was bedeutet, dass diese Regel nicht richtig funktioniert.

ip rule add from 172.17.42.1 table docker

Versuchen Sie es stattdessen

ip rule add from 172.17.0.0/16 table docker

Das hat leider nicht geklappt. Meine Container wurden immer noch zum selben Standard-Gateway wie der Host geroutet. Hier ist, was ich lief: ip rule add from 172.17.0.0/16 table docker ip route add default via 192.168.1.2 dev eth1 table docker ip route flush cache /etc/init.d/docker restart Aus dem Container lief ich eine Traceroute und der erste Sprung war 10.1.1.1, als es 192.168.1.1 gewesen sein sollte
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.