更改 docker 容器中的默认路由

新手上路,请多包涵

我有一个连接到两个网络的 docker 容器,默认网桥和自定义网桥。通过默认,它只链接到默认网络中的另一个容器,并通过自定义网桥,它获取本地网络中的 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

但重启后就没有了。我该如何改变呢?

更新: 显然, 网络的字典顺序 也可能是问题的一部分。当我有机会时,我会测试它。

原文由 martin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

如果我理解这个问题,问题是: 重新启动连接到多个网桥的容器时,如何更喜欢使用网桥作为默认路由?

我搜索了可用选项并进行了一些测试,我没有找到任何 docker 命令行选项来指定默认路由或在容器连接到多个网桥时首选网桥作为默认值。当我重新启动连接到默认网桥( bridge )和自定义网桥(您的 homenet )的容器时,默认路由自动设置为使用默认网桥(网关 172.17.0.1 )。这对应于您描述的行为。

解决方案 1:在运行命令中指定一个启动脚本,该脚本负责更改默认路由并启动容器必须运行的服务

 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

该解决方案避免了对容器授予特殊权限,并将更改路由的责任转移给主机。

原文由 Silicium14 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用 nsenter 命令进入容器的命名空间,然后在其中执行命令。左右:

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

原文由 Yeats Raw 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进