我有一个连接到两个网络的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
但重启后就已消失了。我怎么能改变它?
更新:显然,the lexicographical order of the networks也可能是此问题的一部分。我有机会的时候会测试它。
答案 0 :(得分:18)
如果我理解这个问题,问题是:重新启动连接到多个网桥的容器时,如何选择使用网桥作为默认路由?
我搜索了可用的选项并进行了一些测试,我没有找到任何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
的输出,并将docker events --filter "container=container1" |\
awk '/container start/ { system("/path/to/route_setting.sh") }'
连接到自定义网桥,然后将其连接到route_setting.sh
。
解决方案2:在容器启动事件上设置容器默认路径
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
{{1}}包含更改容器默认路由的说明:
{{1}}
此解决方案避免为容器提供特殊权限,并将路由更改责任转移给主机。
答案 1 :(得分:1)
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 :(得分:0)
@ Silicium14
非常感谢您的第二个解决方案。我花了很长时间找到一种在容器启动时设置路线的方法。我需要根据我的需要对行进行一些更改,因为我需要提供从 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 类型的容器的事件 使用-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 '{}' \;
答案 3 :(得分:-1)
带有选项 例如:
dockerd --bip 10.1.0.1/24
如果您使用 ubuntu 14.04 ,请更改
/etc/default/docker
如果您使用 ubuntu 16.04 ,请更改
/lib/systemd/system/docker