像许多人一样,在整理了几个docker-compose项目后,当我尝试启动一个项目时遇到了错误:

ERROR: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
具体来说,当我有 31 个bridge网络并尝试提出一个将总数增加到 32 个的 compose 项目时,就会发生这种情况。

搜索了一下,发现这个问题比较普遍,可以通过扩大默认地址池的范围来解决。

在我告诉您更多信息之前 - 这是有关如何解决该问题的概要。

TL;DR - 如何修复它
问题是默认配置使每个桥接网络都非常大,这意味着可用空间只能容纳 32 个桥接网络。

将以下内容添加到/etc/docker/daemon.json:

{
"default-address-pools" : [
{
"base" : "172.17.0.0/12",
"size" : 20
},
{
"base" : "192.168.0.0/16",
"size" : 24
}
]
}
这将每个桥接网络的容量减少了1/16,并允许您拥有16数倍的桥接网络。

不用担心,最小的桥接网络仍然能够容纳256主机,最大的也可以容纳4096主机

如果您真的关心为什么这是一件事,请继续阅读
我发现了一些有用的资源:

@TheOrangeOne关于该主题的博客文章 ,其中描述了如何添加额外的池
本文虽然简洁,但存在缺陷,因为它包含IANA 私有地址范围之外的地址范围,因此可能与公共可路由地址发生冲突。
capstonec.com 关于 在 Docker 企业版中配置地址池的帖子。
有几件事我仍然想知道:

不配置的情况下,默认的地址池是多少?
注意:从现在开始,我将把这些池称为“普通”池,以避免与术语“默认”混淆
如果我想编写一个与普通池相同的配置,我该怎么做?
如果我想编写一个保留普通池的配置,而不是替换它们,并且仅扩展它们/仅添加新池,我该怎么做?
为什么默认配置最多只允许 31 个网络?
在我们开始之前,这里有一些术语,我假设您已经了解:

术语和假设知识
假定的知识
您了解 IP 地址是什么
理想情况下,您熟悉以下符号:*
十六进制表示法,
二进制记数法
如何在十六进制和二进制之间转换。
术语示例
为了帮助解释这些术语,我将给出一个可能熟悉的示例:

考虑一下您的调制解调器。如果您曾经设置过 wifi 密码,您可能已经连接到如下 IP 地址:

192.168.0.1。这是您局域网中的第一个地址。

有关192.168.0.1含义的一些上下文
它只是一个 4 字节的序列(也称为 32 位,因为 1 字节 = 8 位)。
使用字节可以表示的最大无符号十进制数是 255。
要以二进制表示 255dec,您可以编写:1111 1111。 1111 1111表示该字节中的每一位都是1
要以十六进制表示 255dec,您可以编写FF
您可能已经注意到,您的计算机在 LAN 上分配了一个地址,例如:

192.168.0.3

典型的 LAN 设置通常定义一个地址池,从 开始192.168.0.1,一直到192.168.0.255。

这有两个部分:

192.168.0.___
这是您本地网络的前缀。网络中的每个主机都有完全相同的前缀。
__...3
这是您计算机的主机 ID 。这3就是您的计算机与网络上其他任何设备(例如手机)的区别。
条款
网络
可路由主机的块。
例如您的 LAN 网络 (192.168.0.[1-255])
网络掩码
这通常表示为:255.255.255.0、255.255.240.0或类似的内容。
对于给定网络,这定义了给定地址的哪些部分定义了网络 ID。
对于您的 LAN 网络,这将是255.255.255.0
以十六进制表示,这看起来像:FF.FF.FF.00
在二进制中,这看起来像:1111 1111.1111 1111.11111 1111.0000 0000
那是因为对于你的LAN网络来说,192.168.0.___前3个字节都指定了网络前缀
西德
无类别域间路由​​​
用于识别网络和设备的符号。
这基本上看起来像ip.ip.ip.ip/prefix_length:
prefix_len0是& 32(含)之间的整数。
这定义了有多少 IP 地址用于识别网络。
对于您的局域网,192.168.0.

CIDR 为:192.168.0.0/24
最后 8 位(1 个字节)定义给定主机
前 24 位(3 个字节)定义网络
A prefix_lenof/24相当于网络掩码FF.FF.FF.00
未给出配置时的默认地址池是什么(“vanilla”池)?
这些信息比我想象的要容易找到——无论出于什么原因,docker 都没有在我能找到的任何地方正式记录它。

capstonec.com 文章对此进行了非正式的描述:

每个 Docker 节点上本地桥接网络的默认地址池包括 CIDR 范围 172.17.0.0/16 到 172.31.0.0/16 和 192.168.0.0/20 到 192.168.240.0/20。

这很有帮助,但我想要一个更严格的定义 - 我在 Docker 文档的 Issue #8663中找到了这个

docker 的截图#8663

编写与“vanilla”配置等效的配置
如果我们想写一个/etc/docker/daemon.json表达与“vanilla”相同的配置,它看起来像这样:

{
"default-address-pools" : [
{
"base" : "172.17.0.0/12",
"size" : 16
},
{
"base" : "192.168.0.0/16",
"size" : 20
}
]
}
编写扩展的“vanilla”配置
想象一下,我们想要编写一个/etc/docker/daemon.json包含上述地址空间的程序,但添加了一些额外的地址池 - 我们将如何做到这一点?

好吧,快速回答是:我们不能

这是为什么?

IPv4 中的私有地址范围
那么,互联网号码分配机构 (IANA) 为专用网络分配了 3 个范围

专用网络使用的地址范围是:

A 类:10.0.0.0 至 10.255.255.255
B 类:172.16.0.0 至 172.31.255.255
C 类:192.168.0.0 至 192.168.255.255
这些范围之外的任何内容都应被视为公共,因此可能属于外部主机。

让我们考虑一下我们的两个普通地址池:

(Vanilla pool 1)覆盖的地址范围172.17.0.0/12为:172.16.0.1->172.31.255.254
(Vanilla pool 2)覆盖的地址范围192.168.0.0/16为:192.168.0.1->192.168.255.254
这涵盖了 IANA B 级和 C 级范围内的所有内容。它也有可能与您的 LAN 网络发生冲突。

我们还从docker docs #866310.0.0.0/8知道,普通的 swarm 网络池由- Meaning 10.0.0.1->给出10.255.255.255。

这占据了整个 A 级范围。现在,我们不深入配置群地址池,我们将自己限制在 B 类和 C 类范围内。

您可能想知道 - 如果我们只允许使用这两个范围创建 31 个网络,这肯定意味着这些范围不是很大?

你就错了:

192.168.0.0/16可以包含65534个主机,
172.17.0.0/12可以包含 1048574 个主机。
如果您的用例与我的类似,那么您可能有<100正在运行的主机 - 让我们看看我的:

sudo docker ps --filter status=running --quiet | wc -l
26
让我们看看我现在有多少个网络:

sudo docker network ls --filter driver=bridge --quiet | wc -l
31
问题不在于没有足够的空间,而在于默认的网络大小比需要的大得多。

如何配置 docker 以允许 >500 个桥接网络
简而言之,我们需要增加“size”掩码的值:

--- daemon-old.json 2021-09-12 17:56:03.344023200 +1000
+++ daemon-new.json 2021-09-12 17:52:49.274194000 +1000
@@ -2,11 +2,11 @@
"default-address-pools" : [
{
"base" : "172.17.0.0/12",

  •  "size" : 16
    
  •  "size" : 20
    
    },
    {
    "base" : "192.168.0.0/16",
  •  "size" : 20
    
  •  "size" : 24
    
    }
    ]
    }
    新的、改进的配置:

{
"default-address-pools" : [
{
"base" : "172.17.0.0/12",
"size" : 20
},
{
"base" : "192.168.0.0/16",
"size" : 24
}
]
}
恭喜 - 您现在应该能够围绕512桥接网络进行创建。

如果您想知道为什么这有效,请继续阅读。

为什么我们只允许 31 个网络?
默认池由以下公式给出:

{
"default-address-pools" : [
{
"base" : "172.17.0.0/12",
"size" : 16
},
{
"base" : "192.168.0.0/16",
"size" : 20
}
]
}
让我们来分析一下这意味着什么:

池定义1
考虑第一组,

{
"base" : "172.17.0.0/12",
"size" : 16
},
考虑“基础”:
在十六进制中,我们可以将“base”表示为: AC.11.00.00
/12定义了一个网络掩码FF.F0.00.00
这意味着对于基地来说,主机可以属于以下范围:
._h.hh.hh:._0.00.00->._F.FF.FF
考虑“尺寸”:
“size”定义了上面“base”池中分配的给定子网的前缀/网络掩码
“大小”16指定网络掩码:FF.FF.00.00
这意味着对于基础网络的这一部分,主机可以属于以下范围:
..hh.hh:
..00.00->.__.FF.FF
本质上,"size" : 16表示对于给定的 docker 桥接网络,第 16 位之后的所有内容都标识该桥接网络中的唯一主机。

所以基本上我们的二进制定义变成:

nnnn nnnn.nnnn ????.hhhh hhhh.hhhh hhhh

n:这些位是整个网络的前缀
h:对于整个网络的给定子网,这些位唯一标识给定主机
那么是什么?意思呢?

?:这些位在整个网络下 唯一标识给定的子网。*
在我们的示例中,只有 4 个位?,或者一个十六进制数字
这意味着这些?位只能采用16 种独特的组合
0-9,或 AF。
池定义2
{
"base" : "192.168.0.0/16",
"size" : 20
}
考虑“基础”:
十六进制:C0.A8.00.00
/16:
网络掩码:FF.FF.00.00
总范围:
..hh.hh:..00.00->..FF.FF
考虑“尺寸”:
“大小”20指定网络掩码:FF.FF.F0.00
总范围:
.._h.hh:.._0.00->.._F.FF
分离不同的区域:
nnnn nnnn.nnnn nnnn.???? hhhh.hhhh hhhh
这里只有 4?位,意味着该范围也有 16 个可能的不同子网。
让我们通过查看本地计算机上运行的 31 个桥接网络来将其放在一起:

新配置之前的本地桥接网络:
Id range
|
v
AC.10.39.00/24 vdf
AC.11.00.00/24 bridge
AC.12.00.00/16 gollum
AC.13.00.00/16 ghost
AC.14.00.00/16 nextcloud-proxy
AC.15.00.00/16 media_default
AC.16.00.00/16 diskover-proxy
AC.17.00.00/16 keycloak-proxy
AC.18.00.00/16 kibana
AC.19.00.00/16 ytdl
AC.1A.00.00/16 homer
AC.1B.00.00/16 keycloak
AC.1C.00.00/16 logstash
AC.1D.00.00/16 ssh
AC.1E.00.00/16 proxy_default
AC.1F.00.00/16 traefik

Id range
|
v
C0.A8.10.00/20 nextcloud
C0.A8.20.00/20 diskover
C0.A8.30.00/20 calibre-web
C0.A8.40.00/20 ldap
C0.A8.50.00/20 elastic
C0.A8.60.00/20 watchtower
C0.A8.70.00/20 robots
C0.A8.80.00/20 lam
C0.A8.90.00/20 samba
C0.A8.A0.00/20 unmanic
C0.A8.B0.00/20 gotify
C0.A8.C0.00/20 netdata
C0.A8.D0.00/20 gitlab-runner
C0.A8.E0.00/20 huginn
C0.A8.F0.00/20 huginn-proxy
正如我们所看到的,只有一位数字发生了变化:

AC.1_.__池:第3位数字
C0.A8.F_池:第5位数字
新配置后的本地桥接网络:
|
v
AC.10.00.00/20 bridge
AC.10.10.00/20 ghost
AC.10.20.00/20 elastic
AC.10.39.00/24 vdf
AC.10.40.00/20 kibana
AC.10.50.00/20 unmanic
AC.10.60.00/20 diskover
AC.10.70.00/20 keycloak
AC.10.80.00/20 calibre-web
AC.10.90.00/20 ldap
AC.10.A0.00/20 nextcloud
AC.10.B0.00/20 media_default
AC.10.C0.00/20 gollum
AC.10.D0.00/20 watchtower
AC.10.E0.00/20 robots
AC.10.F0.00/20 homer
^
|
Digit Changes

Only these digits change
|
v
AC.11.00.00/20 gotify
AC.11.10.00/20 huginn
AC.11.20.00/20 huginn-proxy
AC.11.30.00/20 lam
AC.11.40.00/20 ytdl
AC.11.50.00/20 netdata
AC.11.60.00/20 diskover-proxy
AC.11.70.00/20 keycloak-proxy
AC.11.80.00/20 nextcloud-proxy
AC.11.90.00/20 samba
AC.11.A0.00/20 gitlab-runner
AC.11.B0.00/20 ssh
AC.11.C0.00/20 logstash
AC.11.D0.00/20 proxy_default
AC.11.E0.00/20 sshportal_default
AC.1F.00.00/16 traefik
标签: docker 网络