Docker桥接与主机网络冲突

27
Docker似乎在容器启动后创建了一个桥接,然后与我的主机网络发生冲突。这不是默认的docker0桥接,而是在容器启动后创建的另一个桥接。我能够根据旧用户指南链接https://docs.docker.com/v17.09/engine/userguide/networking/default_network/custom-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
2个回答

49
当使用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选项。例如:
 # 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网络,从而防止整个172.17.0.0/16被dockerd(在将来的桥接网络中)使用。

172.17.*中找到4个连续的IP,这些IP在主机网络中未被使用,并将它们放入“墓碑”docker bridge中。下面,我假设你的主机网络中未使用的IP为172.17.253.0172.17.253.1172.17.253.2172.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的块。理论上,最小的有效网络子网应该是由总共2个IP(网络标识符+广播)组成的/31。Docker要求最小为/30,可能考虑到网关主机和另一个容器。我随意选择了.253.0,您应该选择您环境中未使用的内容。另请注意,标识符tombstone并没有什么特别之处,您可以将其重命名为任何可以帮助您在几个月后再次找到它的东西。

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}的流量通过刚刚创建的坟墓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
# 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中保留该墓碑网络,但不在容器中使用它。它是一个虚拟的占位符网络。

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

如果想要暂时避免IP冲突,可以使用ip关闭冲突的docker桥接:ip link set dev br-xxxxxxx down(其中xxxxxx表示从route -nip 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


1
这是个很棒的答案,伙计,帮了我很多忙! - Pirozek
1
"/etc/docker/daemon.json" 的语法:"default-address-pools":[ {"base":"172.17.0.0/16","size":24} ] - Antonio Bardazzi
解决方案#0(迄今为止最好的)的最低版本应为Docker 18.09.1(在Linux上)(请参见https://github.com/moby/moby/pull/36396)。 - SebastianH

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接