当使用
docker network create
或通过docker-compose间接创建docker网络时,如果没有明确指定子网范围,dockerd将从
172.N.0.0/16
开始分配一个新的
/16
网络,其中
N
是递增的数字(例如N=17,N=18,N=19,N=20等)。如果在该范围内已经存在一个docker网络(自定义网络或默认的docker bridge网络),则会跳过给定的
N
。您可以在CLI中创建docker bridge时明确指定一个安全的IP范围(即排除您网络中的主机IP),但通常情况下,docker-compose会使用默认值自动创建桥接网络。要可靠地排除这些IP地址需要修改遇到的每个docker-compose.yaml文件。在compose文件中包含特定于主机的内容是不好的实践。相反,可以尝试使用下面列出的三种方法来操作dockerd考虑分配的网络,以强制其“跳过”子网。
方法#0 - 配置守护程序配置文件中的IP池
如果您的docker版本足够新(TODO检查最小版本),并且您有权限配置docker守护程序的命令行参数,则可以尝试向dockerd命令传递
--default-address-pool ARG
选项。例如:
--default-address-pool base=172.24.0.0/13,size=24
你可以在一个etc文件中添加此设置:/etc/default/docker
或者/etc/sysconfig/docker
,具体取决于你的发行版。还有一种方法是在daemon.json中设置此参数(请参阅语法)。
方法1——创建虚拟占位符网络
您可以在172.17.0.0/16
内任何地方创建一个非常小的docker网络,从而防止整个172.17.0.0/16
被dockerd(在将来的桥接网络中)使用。
在172.17.*
中找到4个连续的IP,这些IP在主机网络中未被使用,并将它们放入“墓碑”docker bridge中。下面,我假设你的主机网络中未使用的IP为172.17.253.0
、172.17.253.1
、172.17.253.2
和172.17.253.3
(即172.17.253.0/30
)。
docker network create --driver=bridge --subnet 172.17.253.0/30 tombstone
注意这里的/30
后缀,它定义了一个包含4个不同IP的块。理论上,最小的有效网络子网应该是由总共2个IP(网络标识符+广播)组成的/31
。Docker要求最小为/30
,可能考虑到网关主机和另一个容器。我随意选择了.253.0
,您应该选择您环境中未使用的内容。另请注意,标识符tombstone
并没有什么特别之处,您可以将其重命名为任何可以帮助您在几个月后再次找到它的东西。
Docker将修改您的路由表,以使这4个IP的流量通过新的桥接而不是主机网络进行发送:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.5.1 0.0.0.0 UG 0 0 0 eth1
172.17.253.0 0.0.0.0 255.255.255.252 U 0 0 0 br-c48327b0443d
172.20.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.5.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
注意:172.17.253.{0,1,2,3}的流量通过刚刚创建的坟墓docker桥(br-c4832...)进行处理。 172.17.*中的任何其他IP的流量都会通过默认路由(主机网络)进行处理。我的docker桥(docker0)在172.20.0.1上,这可能看起来不寻常 - 我已经修改了/etc/docker/daemon.json中的bip。有关更多详细信息,请参见此页面。注意:如果存在占用/16的子部分的桥接,则新创建的桥接将跳过该范围。如果我们创建新的docker网络,我们可以看到其余的172.17.0.0/16被跳过,因为该范围并非完全可用。docker network create foo_test
docker network create bar_test
生成的路由表:
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.5.1 0.0.0.0 UG 0 0 0 eth1
172.17.253.0 0.0.0.0 255.255.255.252 U 0 0 0 br-c48327b0443d
172.18.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-c9e1b01f7003
172.19.0.0 0.0.0.0 255.255.0.0 U 0 0 0 br-7ad5611bfa07
172.20.0.0 0.0.0.0 255.255.0.0 U 0 0 0 docker0
192.168.5.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
注意,172.17.0.0/16
中的其余IP地址尚未被使用。新网络保留了 .18.
和 .19.
。向任何在该墓碑网络之外的冲突IP发送流量将通过您的宿主机网络。
您需要在docker中保留该墓碑网络,但不在容器中使用它。它是一个虚拟的占位符网络。
方法#2 -- 关闭冲突的桥接网络
如果想要暂时避免IP冲突,可以使用ip
关闭冲突的docker桥接:ip link set dev br-xxxxxxx down
(其中xxxxxx表示从route -n
或ip link show
中的网桥网络名称)。这将导致路由表中相应的桥接路由条目被删除,而不修改任何docker元数据。
这可能不如上面的方法好,因为每次启动dockerd时都必须关闭接口,如果有任何使用该网桥的容器,还会干扰容器网络。
如果以后方法1无法使用(例如,因为docker试图更聪明地重用IP块的未使用部分),则可以结合两种方法:例如,创建一个大的墓碑网络,占用整个/16
,不在任何容器中使用它,然后关闭它相应的br-x设备。
方法#3 -- 重新配置docker桥占用冲突的/16子区域
作为上述的一种轻微变化,您可以使默认的docker桥与您的主机网络未使用的172.17.*.*
区域重叠。您可以通过更改/etc/docker/daemon.json
中的桥IP(即bip
键)来更改默认的docker桥子网(有关详细信息,请参见此页面)。只需将其设置为您的/16的子区域,例如/24或更小。
我没有测试过这个,但我认为任何新的docker网络都会跳过172.17.0.0/16
的其余部分,并为每个新的桥接分配完全不同的/16
。