Ich habe einen Docker-Container, der mit zwei Netzwerken verbunden ist, der Standardbrücke und einer benutzerdefinierten Brücke. Über die Standardeinstellung ist sie nur im Standardnetzwerk mit einem anderen Container verknüpft. Über die benutzerdefinierte Brücke erhält sie eine IP-Adresse im lokalen Netzwerk.
LAN -- [homenet] -- container1 -- [bridge] -- container2
Sudo docker network inspect homenet
[{ "Name": "homenet",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [{ "Subnet": "192.168.130.0/24",
"Gateway": "192.168.130.8",
"AuxiliaryAddresses": { "DefaultGatewayIPv4": "192.168.130.3" }}]
},
"Internal": false,
"Containers": {
"$cid1": { "Name": "container",
"EndpointID": "$eid1_1",
"MacAddress": "$mac1_1",
"IPv4Address": "192.168.130.38/24", }
},
"Options": { "com.docker.network.bridge.name": "br-homenet" },
"Labels": {}}]
und Brücke:
Sudo docker network inspect bridge
[{
"Name": "bridge",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [{ "Subnet": "172.17.0.0/16" }]
},
"Internal": false,
"Containers": {
"$cid2": {
"Name": "container2",
"EndpointID": "$eid2",
"MacAddress": "$mac2",
"IPv4Address": "172.17.0.2/16",
"IPv6Address": "" },
"$cid1": {
"Name": "container1",
"EndpointID": "$eid1_2",
"MacAddress": "$mac1_2",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": "" }
},
"Options": {
"com.docker.network.bridge.default_bridge": "true",
"com.docker.network.bridge.enable_icc": "true",
"com.docker.network.bridge.enable_ip_masquerade": "true",
"com.docker.network.bridge.Host_binding_ipv4": "0.0.0.0",
"com.docker.network.bridge.name": "docker0",
"com.docker.network.driver.mtu": "1500"
},
"Labels": {}
}]
Dies funktioniert ziemlich gut vom internen Netzwerk aus, jedoch habe ich ein Routing-Problem:
Sudo docker exec -it container1 route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
192.168.130.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
Wie kann ich die Standardroute in 192.169.130.3 ändern, sodass ein Neustart bestehen bleibt?
Ich kann es ändern, während container1 mit läuft
pid=$(Sudo docker inspect -f '{{.State.Pid}}' container1)
Sudo mkdir -p /var/run/netns
Sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
Sudo ip netns exec $pid ip route del default
Sudo ip netns exec $pid ip route add default via 192.168.130.3
das ist aber nach einem neustart weg. Wie kann ich das ändern?
Update: Offensichtlich könnte die lexikographische Reihenfolge der Netzwerke auch Teil des Problems sein. Ich werde es testen, wenn ich eine Chance habe.
Wenn ich die Frage verstehe, ist das Problem: beim Neustart eines Containers, der mit mehreren Bridges verbunden ist, wie soll eine Brücke für die Standardroute bevorzugt werden?
Ich habe nach verfügbaren Optionen gesucht und einige Tests durchgeführt. Ich habe keine Docker-Befehlszeilenoption gefunden, um eine Standardroute anzugeben oder eine Brücke als Standard zu bevorzugen, wenn der Container mit mehreren Brücken verbunden ist. Wenn ich einen Container neu starte, der mit der Standardbrücke (bridge
) und einer benutzerdefinierten Brücke (Ihrem homenet
) verbunden ist, wird die Standardroute automatisch auf die Verwendung der Standardbrücke (Gateway 172.17.0.1
). Dies entspricht dem von Ihnen beschriebenen Verhalten.
Lösung 1: Geben Sie im Befehl run ein Startskript an, mit dem die Standardroute geändert und die Dienste gestartet werden sollen, die der Container ausführen soll.:
docker run \
--cap-add NET_ADMIN \ # to allow changing net settings inside the container
--name container1 \
--restart always \ # restart policy
your_image \
/path/to/your_start_script.sh
Der your_start_script.sh
:
ip route del default
ip route add default via 192.168.130.3
# here goes instructions/services your container is supposed to run
Dieses Skript muss im Container verfügbar sein. Es kann sich in einem freigegebenen Ordner befinden (Option -v
) Oder beim Erstellen eines Images mit einer Docker-Datei geladen werden.
Hinweis: Bevor Sie den Container mit Ihrer benutzerdefinierten Bridge verbinden (docker network connect homenet container1
), Stürzt your_start_script.sh
Ab, da die Standardroute keinem verfügbaren Netzwerk entspricht.
Ich habe getestet, um die Ausgabe von ip route
In container1
Zu protokollieren und mit --restart always
Auszuführen. Nachdem ich es mit der benutzerdefinierten Bridge verbunden habe, hat es die gewünschte Standardroute.
Lösung 2: Festlegen der Container-Standardroute vom Host aus bei Container-Startereignissen
docker events --filter "container=container1" |\
awk '/container start/ { system("/path/to/route_setting.sh") }'
Wobei route_setting.sh
Ihre Anweisungen zum Ändern der Standardroute des Containers enthält:
pid=$(Sudo docker inspect -f '{{.State.Pid}}' container1)
Sudo mkdir -p /var/run/netns
Sudo ln -s /proc/$pid/ns/net /var/run/netns/$pid
Sudo ip netns exec $pid ip route del default
Sudo ip netns exec $pid ip route add default via 192.168.130.3
Diese Lösung vermeidet, dem Container spezielle Berechtigungen zu erteilen, und überträgt die Verantwortung für die Routenänderung auf den Host.
nsenter -n -t $ (Docker inspect --format {{.State.Pid}} $ Dockername) IP-Route etwas hinzufügen.
nsenter -n -t $ (Docker inspect --format {{.State.Pid}} $ Dockername) ip route del etwas.
@ Silicium14
Vielen Dank für Ihre 2. Lösung. Ich habe lange gebraucht, um einen Weg zu finden, Routen beim Start des Containers festzulegen. Ich habe Ihre Zeilen ein wenig nach meinen Bedürfnissen geändert, da ich dem Skript einen Containernamen von docker events angeben muss
Zuerst starte ich den Hörer für meine Veranstaltungen.
docker events --filter 'container=box1' --filter 'container=box2' --filter 'event=start' --filter 'event=stop' --format '{{.Actor.Attributes.name}}'|awk '{ system("/work/route_setting.sh " $1) }'
Ich verwende mehr Filter, da ich die Ereignisse für zwei Container vom Typ start oder stop .__ benötige. Mit --format kann man die Ausgabe sehr gut steuern. Daher wird nur der Containername an awk weitergeleitet. Dadurch wird mein Routing-Skript mit dem richtigen Containernamen ausgelöst.
#!/bin/bash
# exit if no container name provided as $1
[ "x$1" = 'x' ] && exit 1
# holds pid of the docker container
pid=''
# read the pid for container
pid=$(docker inspect -f '{{.State.Pid}}' "${1}" 2>/dev/null)
# if for whatevery reason we get pid 0 avoid setting routes
[ "x$pid" = 'x0' ] && pid=''
if [ "x$pid" != 'x' ] ; then
# let the routing happen
mkdir -p /var/run/netns
ln -s /proc/$pid/ns/net /var/run/netns/$pid
ip netns exec $pid ip route add 10.0.0.0/8 via 10.66.101.1
ip netns exec $pid ip route add 192.168.0.0/16 via 10.66.101.1
fi
# clean up broken symlinks which occur when a container is stopped
# verify that your find supports -xtype l
find /var/run/netns -xtype l -exec rm -f '{}' \;