web-dev-qa-db-ja.com

Dockerコンテナのデフォルトルートを変更する

デフォルトブリッジとカスタムブリッジの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

しかし、それは再起動後に消えます。どうすれば変更できますか?

更新:どうやら、 ネットワークの辞書順 も問題の一部である可能性があります。機会があればテストします。

19
martin

質問を理解した場合、問題は次のとおりです。複数のブリッジに接続されたコンテナを再起動するとき、デフォルトルートに使用するブリッジを優先する方法?

利用可能なオプションを検索し、いくつかのテストを行いましたが、コンテナが複数のブリッジに接続されている場合、デフォルトルートを指定したり、デフォルトとしてブリッジを選択したりする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

このソリューションは、コンテナに特別な許可を与えることを回避し、ルート変更責任をホストに転送します。

19
Silicium14

nsenter -n -t $(docker inspect --format {{.State.Pid}} $ dockername)ip routeは何かを追加します。

nsenter -n -t $(docker inspect --format {{.State.Pid}} $ dockername)ip route del something。

1
Yeats Raw

けいすけ

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 '{}' \;
0
jahlives