Docker似乎在容器开始运行后创建了一个网桥,然后与我的主机网络发生冲突。 这不是默认的网桥 docker0,而是在容器启动后创建的另一个网桥。我能够根据较旧的用户指南链接 https://docs.docker.com/v17.09/engine/userguide/networking/default_network/custom-docker0/配置默认网桥,但是,我不知道如何配置另一个网桥,因此它不会与 172.17 冲突。
当前的问题是,当此网桥变为活动状态时,我的容器无法访问主机网络上的其他系统。
有什么想法吗?
码头工人的版本:
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 网络(例如使用docker network create
或通过 docker-compose 间接创建)而没有明确指定子网范围时,dockerd 会分配一个新的/16
网络,从172.N.0.0/16
开始,其中N
是一个递增的数字(例如 N=17、N=18、N=19、N=20 等)。如果范围内已存在 docker 网络(自定义网络或默认 docker 桥),则会跳过给定的N
。
在 CLI 上创建 docker 网桥(即排除网络中的主机 ip)时,可以显式指定安全 IP 范围。但通常桥接网络是由具有默认块的 docker-compose 自动创建的。要可靠地排除这些 IP,需要修改您遇到的每个 docker-compose.yaml 文件。在撰写文件中包含特定于主机的内容是一种不好的做法。
相反,您可以使用 docker 认为已分配的网络来强制 dockerd "跳过"子网。我在下面概述了三种方法:
方法 #0 -- 在守护程序配置中配置 IP 池
如果您的 docker 版本足够新(TODO 检查最低版本),并且您有权配置 docker 守护程序的命令行参数,则可以尝试将--default-address-pool ARG
选项传递给 dockerd 命令。前任:
# 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,并在"逻辑删除"docker 桥中牺牲它们。下面,我假设ips172.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
,你应该选择环境中未使用的东西。另请注意,标识符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
:ip link set dev br-xxxxxxx down
关闭冲突的 docker 桥(其中 xxxxxx 表示来自route -n
或ip link show
的网桥网络的名称)。这将具有删除路由表中相应网桥路由条目的效果,而无需修改任何 docker 元数据。
这可以说不如上面的方法好,因为每次dockerd启动时,您都必须关闭接口,并且如果有任何容器使用该桥,它会干扰您的容器网络。
如果方法 1 将来停止工作(例如,因为 docker 试图变得更聪明并重用 ip 块中未使用的部分),您可以结合这两种方法:例如,创建一个包含整个/16
的大型逻辑删除网络,不要在任何容器中使用它,然后关闭其相应的 br-x 设备。
方法 #3 -- 重新配置您的 docker 桥以占用冲突的/16 的子部分
作为上述内容的轻微变化,您可以使默认 docker 桥与主机网络中未使用的172.17.*.*
区域重叠。您可以通过更改网桥 ip(即bip
键)/etc/docker/daemon.json
(有关更多详细信息,请参阅此页面)。只需将其设为/16 的子区域,例如在/24 或更小
的区域中。我还没有测试过这个,但我认为任何新的 docker 网络都会跳过172.17.0.0/16
的其余部分,并为每个新网桥分配一个完全不同的/16
。
桥是从 docker-compose 创建的,可以在 compose 文件中进行配置。
在这里找到答案:Docker创建了两个桥,破坏了我的互联网访问