Docker跨主機(jī)通信實(shí)現(xiàn)與分析
前言
docker目前支持以下5種網(wǎng)絡(luò)模式:
- bridge:此時(shí)docker引擎會創(chuàng)建一個(gè)veth對,一端連接到容器實(shí)例并命名為eth0,另一端連接到指定的網(wǎng)橋中(比如docker0),因此同在一個(gè)主機(jī)的容器實(shí)例由于連接在同一個(gè)網(wǎng)橋中,它們能夠互相通信。容器創(chuàng)建時(shí)還會自動(dòng)創(chuàng)建一條SNAT規(guī)則,用于容器與外部通信時(shí)。如果用戶使用了-p或者-Pe端口端口,還會創(chuàng)建對應(yīng)的端口映射規(guī)則。
- host:與宿主機(jī)共享網(wǎng)絡(luò),此時(shí)容器沒有使用網(wǎng)絡(luò)的namespace,宿主機(jī)的所有設(shè)備,如Dbus會暴露到容器中,因此存在安全隱患。
- none:不設(shè)置網(wǎng)絡(luò),相當(dāng)于容器內(nèi)沒有配置網(wǎng)卡,用戶可以手動(dòng)配置。
- container:指定與某個(gè)容器實(shí)例共享網(wǎng)絡(luò)
- network:使用自定義網(wǎng)絡(luò),可以使用docker network create創(chuàng)建,并且默認(rèn)支持多種網(wǎng)絡(luò)驅(qū)動(dòng),用戶可以自由創(chuàng)建橋接網(wǎng)絡(luò)或者overlay網(wǎng)絡(luò)。
默認(rèn)是橋接模式,網(wǎng)絡(luò)地址為172.16.0.0/16,同一主機(jī)的容器實(shí)例能夠通信,但不能跨主機(jī)通信。本文下面將介紹如何使用gre隧道技術(shù)實(shí)現(xiàn)跨主機(jī)通信。
環(huán)境配置
本文使用兩臺主機(jī)A,B模擬實(shí)驗(yàn),這兩臺主機(jī)其實(shí)是virtalbox虛擬機(jī),操作系統(tǒng)為ubuntu14.04,均配置有兩張網(wǎng)卡,網(wǎng)卡配置如下:
- eth0:與宿主機(jī)橋接,連接公網(wǎng)
- eth1:host only網(wǎng)卡,分配的ip地址為192.168.56.0/24,連接在同一個(gè)host only的網(wǎng)卡能夠互相通信
其中A主機(jī)網(wǎng)絡(luò):
- eth0: 172.16.1.24(公司內(nèi)網(wǎng)IP,能夠通外網(wǎng))
- eth1: 192.168.56.4
B主機(jī)網(wǎng)絡(luò):
- eth0: 172.16.1.178(公司內(nèi)網(wǎng)IP,能夠通外網(wǎng))
- eth1: 192.168.56.5
兩臺主機(jī)需要安裝以下軟件包:
- Docker,實(shí)驗(yàn)時(shí)使用的***版本1.11,快速安裝:
- curl -sSL https://get.docker.com/ | sh
- Openvswitch, 安裝方法:
- sudo apt-get install openvswitch-switch
- bridge-utils,也可以不安裝,使用ovs-vsctl。
Docker配置
兩臺主機(jī)的容器能夠通信,不能出現(xiàn)網(wǎng)絡(luò)重疊,因此設(shè)置不同的網(wǎng)絡(luò):
- A: 10.103.100.0/24
- B: 10.103.200.0/24
并且為了加速鏡像拉取,使用靈雀云鏡像。***A主機(jī)配置文件/etc/default/docker如下:
- DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://houchaohann.m.alauda.cn --bip=10.103.100.1/24 --fixed-cidr=10.103.100.0/24"
B主機(jī)配置文件/etc/default/docker如下:
- DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://houchaohann.m.alauda.cn --bip=10.103.200.1/24 --fixed-cidr=10.103.200.0/24"
分別重啟A、B主機(jī)Docker服務(wù):
- sudo service docker restart
此時(shí)A主機(jī)docker0網(wǎng)橋地址為10.103.100.1,B主機(jī)docker0網(wǎng)橋地址為10.103.200.1。
在A主機(jī)上ping 10.103.200.1顯然不通,同理B主機(jī)ping不通A主機(jī)網(wǎng)橋。
隧道配置
在A主機(jī)上創(chuàng)建一個(gè)網(wǎng)橋(使用ovs-vsctl,不要使用brctl):
- sudo ovs-vsctl add-br docker_tunnel
將gre0接口加入到網(wǎng)橋docker_tunnel, 創(chuàng)建一個(gè)GRE隧道添加到網(wǎng)橋中并配置遠(yuǎn)端IP,注意:我們在eth1之上建立隧道,因此需要使用eth1 IP地址:
- sudo ovs-vsctl add-port docker_tunnel gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.56.5
此時(shí):
- fgp@ubuntu-4:~$ sudo ovs-vsctl show
- 2189345f-d4fb-4915-ab97-4c65a8d9ffe0
- Bridge docker_tunnel
- Port "gre0"
- Interface "gre0"
- type: gre
- options: {remote_ip="192.168.56.5"}
- Port docker_tunnel
- Interface docker_tunnel
- type: internal
- ovs_version: "2.0.2"
把docker_tunnel加入到docker0網(wǎng)橋中:
- sudo brctl addif docker0 docker_tunnel
增加路由:
- sudo ip route add 10.103.200.0/24 via 192.168.56.5 dev eth1
此時(shí)路由表:
- fgp@ubuntu-4:~$ sudo route -n
- Kernel IP routing table
- Destination Gateway Genmask Flags Metric Ref Use Iface
- 0.0.0.0 172.16.1.1 0.0.0.0 UG 0 0 0 eth0
- 10.103.100.0 0.0.0.0 255.255.255.0 U 0 0 0 docker0
- 10.103.200.0 192.168.56.5 255.255.255.0 UG 0 0 0 eth1
- 172.16.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
- 192.168.56.0 0.0.0.0 255.255.255.0 U 0 0 0 eth1
驗(yàn)證A主機(jī)是否能和B通信:
- fgp@ubuntu-4:~$ ping -c 2 -w 1 10.103.200.1
- PING 10.103.200.1 (10.103.200.1) 56(84) bytes of data.
- 64 bytes from 10.103.200.1: icmp_seq=1 ttl=64 time=0.339 ms
- --- 10.103.200.1 ping statistics ---
- 1 packets transmitted, 1 received, 0% packet loss, time 0ms
- rtt min/avg/max/mdev = 0.339/0.339/0.339/0.000 ms
同樣在B主機(jī)執(zhí)行相同步驟:
- sudo ovs-vsctl add-br docker_tunnel
- sudo ovs-vsctl add-port docker_tunnel gre0 -- set Interface gre0 type=gre options:remote_ip=192.168.56.4
- sudo brctl addif docker0 docker_tunnel
- sudo ip route add 10.103.100.0/24 via 192.168.56.4 dev eth1
驗(yàn)證B主機(jī)是否能夠和A通信:
- fgp@ubuntu-5:~$ ping -c 2 -w 1 10.103.100.1
- PING 10.103.100.1 (10.103.100.1) 56(84) bytes of data.
- 64 bytes from 10.103.100.1: icmp_seq=1 ttl=64 time=0.336 ms
- 64 bytes from 10.103.100.1: icmp_seq=2 ttl=64 time=0.409 ms
- --- 10.103.100.1 ping statistics ---
- 2 packets transmitted, 2 received, 0% packet loss, time 999ms
- rtt min/avg/max/mdev = 0.336/0.372/0.409/0.041 ms
驗(yàn)證docker容器跨主機(jī)通信
A主機(jī)創(chuàng)建ubuntu14.04容器:
- docker run -t -i --rm --name from-A --hostname from-A ubuntu:14.04 bash
在容器內(nèi)部查看ip地址:
- # from-A
- ifconfig eth0 | grep 'inet addr' | cut -d ':' -f 2 | cut -d ' ' -f 1
- # 10.103.100.2
B主機(jī)創(chuàng)建ubuntu14.04容器:
- docker run -t -i --rm --name from-A --hostname from-B ubuntu:14.04 bash
在容器內(nèi)部查看地址:
- # from-B
- ifconfig eth0 | grep 'inet addr' | cut -d ':' -f 2 | cut -d ' ' -f 1
- # 10.103.200.2
在A容器實(shí)例上ping B容器實(shí)例:
- # from-A
- ping 10.103.200.2
輸出:
- root@from-A:/# ping -c 2 -w 1 10.103.200.2
- PING 10.103.200.2 (10.103.200.2) 56(84) bytes of data.
- 64 bytes from 10.103.200.2: icmp_seq=1 ttl=62 time=0.510 ms
- --- 10.103.200.2 ping statistics ---
- 1 packets transmitted, 1 received, 0% packet loss, time 0ms
- rtt min/avg/max/mdev = 0.510/0.510/0.510/0.000 ms
我們發(fā)現(xiàn),在主機(jī)A的容器成功ping通主機(jī)B的容器,實(shí)現(xiàn)了跨主機(jī)通信!
使用docker-swarm實(shí)現(xiàn)跨主機(jī)容器通信
docker的overlay的網(wǎng)絡(luò)驅(qū)動(dòng)支持跨主機(jī)通信,這個(gè)實(shí)現(xiàn)在libnetwork中基于內(nèi)置的VXLAN實(shí)現(xiàn)以及docker的libkv庫。使用overlay網(wǎng)絡(luò)需要依賴K-V Store,目前支持的K-V Store包括etcd、Consul、Zookeeper。
本來想直接使用docker啟動(dòng)consul的,后來發(fā)現(xiàn)docker daemon啟動(dòng)依賴consul,因此只能先按照consul。首先到官方下載安裝包:下載地址,解壓縮后,只有一個(gè)二進(jìn)制文件,直接運(yùn)行即可:
- nohup ./consul agent -dev -advertise 172.16.1.24 -client 0.0.0.0 &
注意: 該服務(wù)在A機(jī)器上運(yùn)行,172.16.1.24務(wù)必配成能夠連接外網(wǎng)的IP地址,否則后面啟動(dòng)Swarm容器時(shí)內(nèi)部無法通信!
然后修改A、B服務(wù)的daemon配置文件/etc/default/docker:
- DOCKER_OPTS="--cluster-store=consul://172.16.1.24:8500 --cluster-advertise=eth0:2375"
- DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://houchaohann.m.alauda.cn -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock"
重啟docker服務(wù):
- sudo service docker restart
執(zhí)行docker info必須包含以下信息:
- Cluster store: consul://172.16.1.24:8500
- Cluster advertise: 172.16.1.24:2375
接著我們需要部署Docker Swarm集群,詳細(xì)過程參考手動(dòng)部署docker-swarm集群。
***創(chuàng)建overlay網(wǎng)絡(luò):
- docker network create --driver overlay --subnet 10.103.240.0/24 test
其中--dirver指定為overlay,并指定我們需要的子網(wǎng)地址,名稱為test,通過docker network ls可以檢查我們創(chuàng)建的網(wǎng)絡(luò)是否成功:
- fgp@ubuntu-5:~$ docker network ls | grep test
- 7eef808f272b test overlay
此時(shí)overlay網(wǎng)絡(luò)創(chuàng)建完畢。我們測試其是否支持跨主機(jī)通信,首先我們創(chuàng)建一個(gè)ubuntu容器,命名為ubuntu-1,并使用我們剛剛創(chuàng)建的網(wǎng)絡(luò):
- docker run -t -i -d --net test --name ubuntu-1 ubuntu:14.04
接著我們創(chuàng)建***個(gè)ubuntu容器,此時(shí)為了保證它不和ubuntu-1調(diào)度在同一臺主機(jī)上,我們需要使用docker swarm的filter,指定affinity,如下:
- docker run -t -i -d --net test --name ubuntu-2 -e affinity:container!=~ubuntu-1 ubuntu:14.04
運(yùn)行docker ps:
- docker ps
- fgp@ubuntu-5:~$ docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- ba5018dfe26e ubuntu:14.04 "/bin/bash" 2 minutes ago Up Less than a second ubuntu-5/ubuntu-1
- bedd266cddaa ubuntu:14.04 "/bin/bash" 14 hours ago Up 41 seconds ubuntu-4/ubuntu-2
由此可知,兩個(gè)ubuntu容器運(yùn)行在不同的主機(jī)上,符合我們的測試要求。分別獲取ubuntu-1和ubuntu-2的ip地址:
- fgp@ubuntu-5:~$ docker inspect -f '' ubuntu-1
- 10.103.240.2
- fgp@ubuntu-5:~$ docker inspect -f '' ubuntu-2
- 10.103.240.3
可見ubuntu-1的ip地址為10.103.240.2,ubuntu-2的ip地址為10.103.240.3,我們在ubuntu-1上ping ubuntu-2地址:
- fgp@ubuntu-5:~$ docker exec -t -i ubuntu-1 ping -c 2 10.103.240.3
- PING 10.103.240.3 (10.103.240.3) 56(84) bytes of data.
- 64 bytes from 10.103.240.3: icmp_seq=1 ttl=64 time=0.559 ms
- 64 bytes from 10.103.240.3: icmp_seq=2 ttl=64 time=0.661 ms
- --- 10.103.240.3 ping statistics ---
- 2 packets transmitted, 2 received, 0% packet loss, time 999ms
- rtt min/avg/max/mdev = 0.559/0.610/0.661/0.051 ms
結(jié)果發(fā)現(xiàn),不在同一主機(jī)的ubuntu-1和ubuntu-2能夠正常通信!
【本文是51CTO專欄作者“付廣平”的原創(chuàng)文章,如需轉(zhuǎn)載請通過51CTO獲得聯(lián)系】