菜鸟查了很多资料才找到解决办法,Hats off to the shares!
https://blog.csdn.net/lvshaorong/article/details/69950694
问题需求:
先说我的需求:
简单说:Centos上启动了几个容器,我要通过与Centos在同一局域网下的Win 10 PC去访问这些docker,但是Win 10 和 容器没有在一个网段下,不能直接通信。
具体点:我把Centos作宿主机,利用Docker启动一个hadoop集群,我要通过与Centos在一个局域网下的Win10 PC机通过Java API的方式与集群中的节点进行通信。其实这个需求是我在实验中遇到问题后一步步定位到的,更具体地问题解决过程可以看我的另一篇文章。
我们知道,在Docker启动时会产生虚拟网卡,可以把这个网卡理解为一个虚拟交换机,然后每个容器都连接在这个交换机下,每个容器都拥有自己单独的网卡和IP。现在整理下我们的需求中大致的网络拓扑:
Centos宿主机(假设IP为192.168.1.237)和Win 10 (假设IP为192.168.1.135)在同一局域网下,Centos上运行多个docker(假设所处网段为172.19.0.1/16)。这样的拓扑结构下,Centos宿主机可以和其上运行的容器通信,Centos宿主机可以和Win 10通信。
通过查找各种资料,看到一些解决方案,比如,让容器使用静态独立外部IP等,由于我只是在学习hadoop的时候把Docker作为一个使用工具,不想花费太多时间在Docker上,所以希望尽可能简单的解决问题,最终决定了使用文章开头提到的参考资料。这个方案下的解决思路:
解决方案思路:
Centos宿主机查看网卡和IP:
[root@centos7 ~]# ifconfig br-af4e4c5cd5b4: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.19.0.1 netmask 255.255.0.0 broadcast 172.19.255.255 inet6 fe80::42:6cff:fe9b:7ed2 prefixlen 64 scopeid 0x20<link> ether 02:42:6c:9b:7e:d2 txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 656 (656.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500 inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255 inet6 fe80::42:f7ff:feb9:485d prefixlen 64 scopeid 0x20<link> ether 02:42:f7:b9:48:5d txqueuelen 0 (Ethernet) RX packets 165569 bytes 5882890 (5.6 MiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 24244 bytes 81774073 (77.9 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 192.168.1.237 netmask 255.255.255.0 broadcast 192.168.1.255 inet6 fe80::1823:15e9:2383:bb13 prefixlen 64 scopeid 0x20<link> ether 00:0c:29:fd:d2:c8 txqueuelen 1000 (Ethernet) RX packets 5306454 bytes 1201239143 (1.1 GiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 354841 bytes 298525072 (284.6 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10<host> loop txqueuelen 1000 (Local Loopback) RX packets 135 bytes 9108 (8.8 KiB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 135 bytes 9108 (8.8 KiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 veth0b92e02: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet6 fe80::d02a:1bff:fe77:4d9a prefixlen 64 scopeid 0x20<link> ether d2:2a:1b:77:4d:9a txqueuelen 0 (Ethernet) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 8 bytes 656 (656.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
这里面br-af4e4c5cd5b4和docker0都是Docker创建的虚拟网卡,其中docker0是Docker启动时自己创建的,br-af4e4c5cd5b4是我为我的集群自定义的网络,都是桥接模式,这里我以br-af4e4c5cd5b4介绍,在看文章的你可能直接使用的docker0,也可能也是制定了自定义的网络,但是都没差别的,类比过去就好 ,主要注意IP就成。ens160这块网卡就是与Win 10在同一局域网下。
通过在Centos宿主机查看路由信息可以看出:因为有了这两块网卡,Centos知道到目标地址为172.19.0.0/16以及到192.168.1.0/24的路由。从下面的结果可以看出,172.19.0.0/16网段的数据包通过br-af4e4c5cd5b4发出,192.168.1.0/24数据包通过ens160发出。
[root@centos7 ~]# ip route default via 192.168.1.1 dev ens160 proto dhcp metric 100 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 172.19.0.0/16 dev br-af4e4c5cd5b4 proto kernel scope link src 172.19.0.1 192.168.1.0/24 dev ens160 proto kernel scope link src 192.168.1.237 metric 100
因为有了br-af4e4c5cd5b4,所以Centos可以和dockers通信,Centos在于dockers通信时使用的IP是172.19.0.1;因为有了ens160,所以Centos可以和Win 10通信,Centos于Win 10通信时使用的IP是192.168.1.237。
在容器里面,查看下容器的网卡和IP,这个容器的IP为172.19.0.2
[root@hadoop-0 /]# ifconfig eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500 inet 172.19.0.2 netmask 255.255.0.0 broadcast 172.19.255.255 ether 02:42:ac:13:00:02 txqueuelen 0 (Ethernet) RX packets 8 bytes 656 (656.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 loop txqueuelen 1000 (Local Loopback) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
查看下Win 10 的网卡和IP,(只贴出与Centos通信的网卡的信息),Win 10 IP为192.168.1.135。
无线局域网适配器 WLAN: 连接特定的 DNS 后缀 . . . . . . . : 本地链接 IPv6 地址. . . . . . . . : fe80::d9ab:19ac:60d:8c5d%19 IPv4 地址 . . . . . . . . . . . . : 192.168.1.135 子网掩码 . . . . . . . . . . . . : 255.255.255.0 默认网关. . . . . . . . . . . . . : 192.168.1.1
结合上面的网络拓扑,现在如果我想让Win 10与dockers通信是不成功的,因为Win 10 不知道到172.19.0.0/16的路由,只能把数据包发送给路由器一,但是路由器一也不知道到172.19.0.0/16的路由,所以不能ping通。
为了解决这个问题,只需要告诉Win 10 或 路由器一 到172.19.0.0/16的路由就好,而知道这个路由的设备就是我们的Centos,所以把172.19.0.0/16到Win 10 或 到路由器一的数据包转发给Centos(192.168.1.237)就可以了。
具体解决方案:
在Win 10 中添加静态路由:
route add 172.19.0.1/16 192.168.1.237
然后在Win 10下ping某个容器的ip可以ping通:
C:WINDOWSsystem32>ping 172.19.0.2 正在 Ping 172.19.0.2 具有 32 字节的数据: 来自 172.19.0.2 的回复: 字节=32 时间=1ms TTL=63 来自 172.19.0.2 的回复: 字节=32 时间=1ms TTL=63 来自 172.19.0.2 的回复: 字节=32 时间<1ms TTL=63 ……
(在路由器一中添加路由的方法我没有尝试;另外,文章开头的参考方案中需要删除宿主机内的一条iptables,但是我没有删除成功,删除以后反而失败了,具体原因还不清楚)
另外,虽然已经ping通,但是在我的使用场景下,telnet端口还是不通,最后无奈关闭了我的宿主机的防火墙,很不优雅,以后再解决吧,也希望有大神提供解决方案。