docker虚拟ip和项目地ip冲突问题解决
问题描述:
今天项目地的实施跟我说,有两台服务器部署的服务用项目地的内网访问,访问不了(ping都ping 不通),而用vpn来连接却是可以,网管也看过了,发现不了问题。
项目地是用docker swarm来部署的。总共有4台服务器 分别是: 192.168.54.53
, 192.168.54.54
, 192.168.54.57
, 192.168.54.58
。57
是集群的主节点。 53
和54
这两台服务器ping不通, 57
和58
可以ping通也可以访问。
最后通过查询docker的网络
docker network ls
docker inspect docker_gwbridge
发现,53
和54
的docker_gwbridge这个网段是172.18.0.1
而项目地网段是172.18.171.1
。 我心想网段的前两位相同,但是第三位不同,应该不存在ip冲突吧。
再看看57
和58
这两台服务器的docker_gwbridge,结果发现都是172.16.0.1
网段。我看了一下53和54的装的服务其实不多。就把53的退出了docker swarm 集群,并且把docker_gwbridge删除。
docker swarm leave --force 退出集群
docker node rm docker_gwbridge 删除docker_gwbridge网络
最后发现学校局域网可以ping通53了。
原理分析:
去跟同事讨论了一波。我同事说他写了一篇HTTP和IP通信原理,给我讲了一下大概为什么会这样。
通过命令 route -n
, 看到网络层的ip路由表
从下往上一个一个的做路由筛选,我要ping项目地的一台电脑ip: 172.18.171.251
。
第一:用172.18.171.251
和 最下面的genmask: 255.255.255.0
做与操作得到的是结果是:172.18.171.0 和 192.168.54.0不一致,继续往上走
第二: 用172.18.171.251
和 最倒数第二个的genmask:255.255.0.0 做与操作得到的是结果是:172.18.0.0和172.18.0.0一摸一样,所以他会走docker_gwbridge这个网关。
所以这就解析了为什么ip前两位相同也会造成IP冲突了
更加快捷确定问题的方法:
输入 arp -a
查看链路层协议:
这里就可以很清晰的看到ping的时候走的是哪个网关了。就能很快的确定了docker和项目地网络是否ip冲突了
问题解决:
指定docker_gwbridge的ip网段和学校的ip网段不一致就能解决问题了,然后再让该机器重新加入到集群里
docker network create \
--subnet 172.21.0.0/20 \
--gateway 172.21.0.1 \
-o com.docker.network.bridge.enable_icc=false \
-o com.docker.network.bridge.name=docker_gwbridge \
docker_gwbridge
docker_gwbridge解析
docker_gwbridge: 容器收发南北向报文的网络。他在本质上还是一个local的bridge网络,但是他是我们实现多个host之间的container通信的基础。通常情况下,当我们在链接swarm nodes的时候,docker_gwbridge网络就会被在每一个swarm节点上自动创建出来
在容器里使用traceroute baidu.com
这个命令可以查看,网络到baidu.com的路程是怎样的
bash-4.4# traceroute baidu.com
traceroute to baidu.com (39.156.69.79), 30 hops max, 46 byte packets
1 172.21.0.1 (172.21.0.1) 0.031 ms 0.022 ms 0.020 ms
2 192.168.54.254 (192.168.54.254) 1.473 ms 1.212 ms 1.125 ms
3 * * *
可以看到会利用172.21.0.1 网卡到宿主机然后再让宿主机到外面的网络,其实docker_gwbridge就给了一个连接到宿主机。我在网上找了副图:
因为docker网络实现网络隔离,是通过network namespace来管理的,此时想让两个namespace网络连通起来要利用veth pair (Virtual Ethernet Pair),这是一个成对的端口,可以实现上述功能:
可以安装bridge-utils,去查看宿主机的键值对
yum install bridge-utils
brctl show
结果如下:可以看到veth开头的那些就是veth pair的名字,他们是
[root@ismp ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424e01b403 no
docker_gwbridge 8000.02420ae464b2 no veth279e439
veth47e8c5c
veth5f44916
veth65db808
veth6b7356d
veth78717d6
veth7923c17
veth93615a9
vetha391c05
vethcd7ae02
vethee59ae2
具体的我也说不清楚。大家可以搜一下linux网络隔离的文章看看