デフォルトブリッジとカスタムブリッジの2つのネットワークに接続されているドッカーコンテナーがあります。デフォルトを介して、デフォルトネットワーク内の別のコンテナにのみリンクされ、カスタムブリッジを介して、ローカルネットワーク内のIPアドレスを取得します。
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": {}}]
とブリッジ:
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": {}
}]
これは内部ネットワークからはうまく機能しますが、ルーティングの問題があります。
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
再起動が続くようにデフォルトルートを192.169.130.3に変更するにはどうすればよいですか?
Container1の実行中に変更できます
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
しかし、それは再起動後に消えます。どうすれば変更できますか?
更新:どうやら、 ネットワークの辞書順 も問題の一部である可能性があります。機会があればテストします。
質問を理解した場合、問題は次のとおりです。複数のブリッジに接続されたコンテナを再起動するとき、デフォルトルートに使用するブリッジを優先する方法?
利用可能なオプションを検索し、いくつかのテストを行いましたが、コンテナが複数のブリッジに接続されている場合、デフォルトルートを指定したり、デフォルトとしてブリッジを選択したりするdockerコマンドラインオプションは見つかりませんでした。デフォルトブリッジ(bridge
)とカスタムブリッジ(homenet
)に接続されたコンテナを再起動すると、デフォルトルートは自動的にデフォルトブリッジ(ゲートウェイ172.17.0.1
)。これは、説明する動作に対応します。
解決策1:デフォルトのルートを変更し、コンテナが実行する必要があるサービスを開始するために、担当するrunコマンドで開始スクリプトを指定します:
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
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
このスクリプトは、コンテナー内で使用可能でなければなりません。共有フォルダー(-v
オプション)上にあるか、Dockerfileを使用してイメージの構築時にロードすることができます。
注:コンテナをカスタムブリッジ(docker network connect homenet container1
)に接続する前に、デフォルトルートが利用可能なネットワークに対応していないため、your_start_script.sh
がクラッシュします。
ip route
の出力をcontainer1
で実行して--restart always
で実行し、必要なデフォルトルートを持つカスタムブリッジに接続した後、ログに記録するようにテストしました。
解決策2:コンテナー開始イベントでホストからコンテナーのデフォルトルートを設定する
docker events --filter "container=container1" |\
awk '/container start/ { system("/path/to/route_setting.sh") }'
route_setting.sh
には、コンテナのデフォルトルートを変更するための指示が含まれています。
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
このソリューションは、コンテナに特別な許可を与えることを回避し、ルート変更責任をホストに転送します。
nsenter -n -t $(docker inspect --format {{.State.Pid}} $ dockername)ip routeは何かを追加します。
nsenter -n -t $(docker inspect --format {{.State.Pid}} $ dockername)ip route del something。
けいすけ
2番目のソリューションに感謝します。コンテナの起動時にルートを設定する方法を見つけるのにかなり時間がかかりました。コンテナ名をdocker eventsからスクリプトに提供する必要があるため、必要に応じて行を少し変更しました
まず、イベントのリスナーを開始します。
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) }'
タイプstartまたはstopの2つのコンテナーのイベントが必要なため、さらにフィルターを使用します-formatを使用出力を非常にうまく制御できます。したがって、コンテナ名のみがawkにパイプされます。次に、正しいコンテナ名でルーティングスクリプトが起動されます。
#!/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 '{}' \;