Docker网桥与主机网络冲突

Docker网桥与主机网络冲突,docker,docker-machine,Docker,Docker Machine,Docker似乎在容器开始运行后创建了一个网桥,然后与我的主机网络发生冲突。这不是默认的网桥docker0,而是在容器启动后创建的另一个网桥。我能够根据旧版用户指南链接配置默认网桥,但是,我不知道如何配置另一个网桥,这样它就不会与172.17冲突 当前的问题是,当网桥激活时,我的容器无法访问主机网络上的其他系统 有什么想法吗 docker版本: Version 18.03.1-ce-mac65 (24312) 这是创建的桥梁。有时不是172.17,但有时是 br-f7b50f41d024 Li

Docker似乎在容器开始运行后创建了一个网桥,然后与我的主机网络发生冲突。这不是默认的网桥docker0,而是在容器启动后创建的另一个网桥。我能够根据旧版用户指南链接配置默认网桥,但是,我不知道如何配置另一个网桥,这样它就不会与172.17冲突

当前的问题是,当网桥激活时,我的容器无法访问主机网络上的其他系统

有什么想法吗

docker版本:

Version 18.03.1-ce-mac65 (24312)
这是创建的桥梁。有时不是172.17,但有时是

br-f7b50f41d024 Link encap:Ethernet  HWaddr 02:42:7D:1B:05:A3  
      inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0

桥接器是从docker compose创建的,docker compose可以在compose文件中配置


这里的答案是:

当创建docker网络时(例如使用
docker network create
或通过docker compose间接创建),没有明确指定子网范围,dockerd分配一个新的
/16
网络,从
172.N.0.0/16
开始,其中
N
是一个递增的数字(例如,N=17、N=18、N=19、N=20等)。如果范围内已存在docker网络(自定义网络或默认docker网桥),则跳过给定的
N

您可以在创建docker网桥时明确指定安全IP范围(即排除网络中主机IP的网桥)在CLI上。但通常网桥网络是由docker compose使用默认块自动创建的。要可靠地排除这些IP,需要修改遇到的每个docker-compose.yaml文件。在compose文件中包含特定于主机的内容是错误的做法

相反,您可以使用docker认为已分配的网络,强制docker“跳过”子网。我在下面概述三种方法:

方法#0——在守护程序配置中配置IP池

如果您的docker版本足够新(TODO check minimum version),并且您有权配置docker后台程序的命令行参数,则可以尝试向docker命令传递
--默认地址池ARG
选项。例如:

 # allocate /24 subnets with the given CIDR prefix only.
 # note that this prefix excludes 172.17.*
 --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网络,可以防止dockerd(在未来的网桥网络中)使用整个
172.17.0.0/16

172.17.*
中找到您知道在主机网络中未使用的4个连续IP,并将它们牺牲在“墓碑”docker桥中。下面,我假设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
# created: c48327b0443dc67d1b727da3385e433fdfd8710ce1cc3afd44ed820d3ae009f5
注意这里的
/30
后缀,它定义了一个由4个不同IP组成的块。理论上,最小的有效网络子网应该是一个
/31
,它总共由2个IP组成(网络标识符+广播).Docker要求提供一个
/30
最小值,可能是为了说明网关主机和另一个容器。我随意选择了
.253.0
,您应该选择一些在您的环境中不使用的内容。另外请注意,标识符
墓碑
没有什么特殊之处,您可以将其重命名为任何有助于您记住是什么内容的内容当你几个月后再次找到它时,它就在那里

Docker将修改您的路由表,为这4个IP发送流量,以通过新网桥而不是主机网络:

# output of route -n
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}的流量通过刚刚创建的墓碑码头桥(br-c4832…)。172.17.*中任何其他IP的流量将通过默认路由(主机网络)。我的码头桥(docker 0)是在172.20.0.1上,这可能看起来很不寻常——我已经在/etc/docker/daemon.json中修改了
bip
来实现这一点。有关更多详细信息,请参阅

扭曲之处:如果存在一个桥接器甚至占据了a/16的一个子部分,那么创建的新桥接器将跳过该范围。如果我们创建新的docker网络,我们可以看到,
172.17.0.0/16
的其余部分将被跳过,因为该范围并不完全可用

docker network create foo_test
# c9e1b01f70032b1eff08e48bac1d5e2039fdc009635bfe8ef1fd4ca60a6af143
docker network create bar_test
# 7ad5611bfa07bda462740c1dd00c5007a934b7fc77414b529d0ec2613924cc57
生成的路由表:

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 network create --driver=bridge --subnet 172.17.253.0/30 tombstone
# created: c48327b0443dc67d1b727da3385e433fdfd8710ce1cc3afd44ed820d3ae009f5
您必须在docker中保留墓碑网络,但不能在容器中使用它。它是一个虚拟占位符网络

方法#2——关闭冲突的网桥网络

如果您希望暂时避免IP冲突,可以使用
IP
IP-linkset-dev br-xxxxxxx down
(其中xxxxxx表示
route-n
IP-link show
中的网桥网络名称)。这将在不修改任何docker元数据的情况下,删除路由表中相应的网桥路由条目

这可能不如上面的方法好,因为每次dockerd启动时都可能需要关闭接口,如果有任何容器使用该网桥,这将干扰容器网络

如果方法1在将来停止工作(例如,因为docker试图变得更聪明并重用ip块中未使用的部分),您可以将这两种方法结合起来:例如,使用整个
/16
创建一个大型墓碑网络,不在任何容器中使用它,然后将其相应的br-x d