Peter_Matthew的博客

一种解决 Docker Compose 网段冲突的方法

2022-09-06

本文共1.4k字,大约需要阅读4分钟。

本文提出了一种可以解决使用 docker compose 的容器其默认网段172.17.0.0/16与实际网络环境网段冲突问题的方法——重建网桥。

0x00 引言

为了方便校内举行算法编程比赛,我们在学校服务器上通过 docker compose 搭建了一个OJ,平常使用都没有问题,但有一次在学校综合教学楼B区机房组织进行比赛的时候,发现登不上去,ping服务器也ping不通,只能走WebVPN访问。

在和信网处的老师确认过B区机房可以正常访问服务器的网关后,我和老师确认是因为docker服务造成的网段冲突问题。

0x01 学校的网络结构

我们学校的网络结构大概如下(仅作原理说明,非真实链路结构):

机房的每一台电脑会连接到机房后面的交换机上,机房后面的交换机会和这栋楼的交换机相连接,然后与学校数据中心的主交换机连接。
学校数据中心的主交换机还连接着互联网。
同时,学校的数据中心还放着其他服务器。每台服务器都连着它所在的机柜的交换机,机柜的交换机与服务器管理交换机连接,然后与数据中心的主交换机连接。
然后,服务器会因为docker服务而在路由表上加入连接容器的虚拟网段和网关。

0x02 故障原因

简单来说,就是机房电脑的网段为172.17.0.0/16,而docker的默认网段也为172.17.0.0/16。

比如我将OJ搭建在服务器172.28.11.4这台服务器上,正常情况下,我在宿舍或WebVPN访问时,数据会带着ip地址例如172.31.0.100告知服务器返回数据的位置,服务器接收到数据并进行处理后,准备返回数据,这时发现要返回的地址不在路由表上,于是就向机柜交换机发送数据,让机柜交换机查找目标地址然后一直向上级交换机发送数据,直到找到路由表里有这个地址的交换机,然后向下转发数据,这样我们就可以收到服务器的回复数据。

然而,如果我们在机房电脑172.17.1.2访问服务器,服务器接收到数据并进行处理后,准备返回数据,这时发现要返回的地址在路由表上,这个路由表是docker写上去的,和机房的电脑的网段正好相一致,于是他就会直接通过路由表所写的信息,将数据转发给对应ip的docker容器(即使这个容器不存在),这样,我们就收不到服务器所返回的数据,就会造成无法访问,ping也ping不通。

解决方法也很简单,就是重新分配docker的网段。

0x03 查找容器ip地址

首先列出所有容器

1
docker ps -a

接着,针对容器,进行查询。例如,我们想查找容器 oj-backend (6ada6469fe6d) 的ip地址,输入

1
docker inspect 6ada6469fe6d

IPAddress后面跟的就是容器的ip地址,Gateway后面跟的就是虚拟网关。

我们找到所有我们需要重新分配ip的容器,记住容器名称,例如 oj-backend 、 oj-judge 、 oj-redis 。

0x04 查找网桥

首先列出所有docker网桥

1
docker network ls

接着,针对网桥id,查看详细信息。例如,针对 docker_default (4969db1ebd36) 查找输入以下指令

1
docker network inspect 5bc11281f0ae

Subnet后面跟的就是网桥的网段,Gateway后面跟的就是虚拟网关。

我们找到我们需要重新分配网段的网桥,记住网桥名称,例如 docker_default 。

0x05 停止容器

进入文件所在的文件夹,输入以下指令停止服务。

1
docker-compose stop

0x06 修改容器设置

我们找到 docker-compose.yml 文件,打开编辑,在下面找是否有类似以下内容的部分

1
2
3
4
5
networks:
default:
ipam:
config:
- subnet: "192.168.2.0/24"

如果有,则修改网段,如果没有,则复制上面的内容在文件下方粘贴。

0x07 删除原网桥

我们使用刚刚记住的网桥名称,删除它

1
docker network inspect docker_default

0x08 重启docker服务

使用指令

1
service docker restart

重新启动服务

0x09 重建网桥

进入文件所在的文件夹,输入以下指令就可以重建网桥。

1
docker-compose up -d

此时会报错,这是因为我们虽然新建了网桥,但是容器并未连接到新网桥,我们不用管。此时我们列出所有docker网桥,会发现网桥已经重建好了。

1
docker network ls

0x0a 让容器连接新网桥

使用我们记住的网桥名称和网络名称,使用指令让容器连接到新网桥。

1
2
3
docker network connect docker_default oj-backend
docker network connect docker_default oj-judge
docker network connect docker_default oj-redis

0x0b 启动容器

进入文件所在的文件夹,输入以下指令启动的时候,应该就不会报错了,机房也就可以正常访问了。

1
docker-compose up -d

知识共享许可协议

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

标签: 科技
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏