1、前置知识
在网络通信中,由于交换机能力的限制和网线长度的物理约束,不可能将所有主机连接到同一个交换机上,并处于同一个二层网络中。此外,主机间的 ARP 广播会导致网络瘫痪。因此,需要将主机拆分到多个子网中,然后通过路由器组成三层网络。
IP 地址由网络地址和主机地址两部分组成。例如,在 10.0.0.1/8
中,10
是网络地址,0.0.1
是主机地址。子网掩码(如 /8
)用于区分这两部分。IP 地址实际上是由 32 位二进制组成,x.x.x.x
格式只是为了方便人类阅读而转换成十进制。例如,/8
表示第一段是网络地址,/16
表示前两段是网络地址。
2、问题表现
- Docker 进程无法启动
- 容器端口无法访问,抓包显示有入站但没有出站
3、排查
如果你遇到的是 dockerd
无法启动的情况,可以尝试以下排查方法:
-
查看日志
通常可以在日志中看到类似如下的错误信息(具体日志内容根据实际情况而定):
Error starting daemon: Error initializing network controller: Error creating default "bridge" network: could not find an available, non-overlapping IPv4 address pool among the defaults to assign to the network
-
手动启动
dockerd
通过查看 Docker 服务的启动命令来进行手动启动。可以使用以下命令查看:
grep ExecStart /usr/lib/systemd/system/docker.service
通常会看到类似如下的输出:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
然后手动启动
dockerd
:/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
在输出中,你可能会看到错误信息提示无法创建
docker0
网桥。 -
检查网络接口
使用
ip addr
命令查看网络接口,确认是否存在docker0
和docker_gwbridge
。如果缺少docker0
,基本可以确定是docker0
无法创建导致dockerd
启动失败。
4、解决
找到并解决网段冲突问题是关键。
-
找到占用的网段
默认的
docker0
网段是172.17.0.0/16
,docker_gwbridge
网段是172.18.0.0/24
。需要确认这两个网段是否被占用。- 使用
ping
命令:简单的方法是ping
一下这些网段的地址,如无响应则可能未被占用。 - 查看路由表:使用
route -n
命令查看路由表,确认是否有冲突的网段。
- 使用
-
修改 Docker 占用的网段
在修改前,需要先停止 Docker 进程。如果使用 Docker Service,Docker 会占用四个网段:
docker0
、docker_gwbridge
、ucp
(不常见)、ingress
。其中前三个网段可以通过配置文件配置,第四个需要手动创建。-
编辑配置文件:
配置文件路径为
/etc/docker/daemon.json
,该文件默认不存在,需要手动创建。以下是一个示例配置:{ "bip": "192.168.1.1/24", "default-address-pools": [ {"base": "10.252.0.0/24", "size": 24}, {"base": "10.252.1.0/24", "size": 24}, {"base": "10.252.2.0/24", "size": 24} ] }
注意:
default-address-pools
至少要有两项,按顺序依次为docker0
、docker_gwbridge
、ucp
。配置三个是最佳实践。 -
修改
ingress
网段:ingress
网段需要手动创建。在初始化 Docker Swarm 后,启动 Docker Stack/Service 前,执行以下脚本:yes 'y' | docker network rm ingress yes 'y' | docker network rm my-ingress 2>&1 | true docker network create \ --driver overlay \ --ingress \ --subnet=10.252.3.0/24 \ # 指定 ingress 的网段,不要和 daemon.json 中的网段冲突 --gateway=10.252.3.2 \ --opt com.docker.network.driver.mtu=1200 \ my-ingress
删除
ingress
是异步操作,因此新建一个不同名字的网络以避免重名错误。 -
清理 Docker 缓存:
在重启 Docker 前,最好清理一下 Docker 的缓存:
ip link del dev docker0 ip link del dev docker_gwbridge rm -rf /var/lib/docker/network
-
5、案例
在某环境中,将 docker0
配置为 10.252.0.0/24
后,dockerd
无法启动。排查后发现 route -n
中存在如下路由:
Destination Gateway Genmask Flags Metric Ref Use Iface
10.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 eth0
即 10/8
被占用,导致与 10.252.0.0/24
冲突。联系网管删除 10/8
路由后问题解决。
6、另一种粗糙简单的解决办法
直接手动创建 docker0
网桥:
ip link add name docker0 type bridge
ip addr add dev docker0 10.252.0.1/24
这种方法最简单,但机器重启后 docker0
会自动被删除,因此不持久。而且,这种方法不一定能解决网段冲突问题,只是让 Docker 能启动。
代码运行结果示例
假设我们按照上述步骤修改了 /etc/docker/daemon.json
文件,并重启了 Docker 服务:
-
修改配置文件:
{ "bip": "192.168.1.1/24", "default-address-pools": [ {"base": "10.253.0.0/24", "size": 24}, {"base": "10.253.1.0/24", "size": 24} ] }
-
重启 Docker 服务:
sudo systemctl restart docker
-
检查网络接口:
ip addr show docker0
输出:
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:01 brd ff:ff:ff:ff:ff:ff inet 192.168.1.1/24 brd 192.168.1.255 scope global docker0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:1/64 scope link valid_lft forever preferred_lft forever
通过上述步骤,我们成功修改了 Docker 的默认网段,并解决了 IP 地址冲突问题。希望这篇文章对你有所帮助!