菜鳥查了很多資料才找到解決辦法,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:\WINDOWS\system32>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端口還是不通,最后無奈關閉了我的宿主機的防火牆,很不優雅,以后再解決吧,也希望有大神提供解決方案。