Docker跨主機通訊(九)--技術流ken
容器網路
在前面的部落格中已經詳細講解了幾種網路方案: none, host, bridge,user-defined。但是他們只是解決了單個主機間的容器的通訊問題,並不能實現多個主機容器之間的通訊。本篇部落格將詳細介紹如何實現該功能。
跨主機網路方案包括兩大類:
- docker原生的:overlay和macvlan
- 第三方方案:flannel、weave和calico
本篇部落格將詳細講解overlay以及weave兩種方案。
overlay
Docerk overlay 網路需要一個 key-value 資料庫用於儲存網路狀態資訊,包括 Network、Endpoint、IP 等。Consul、Etcd 和 ZooKeeper 都是 Docker 支援的 key-vlaue 軟體,我們這裡使用 Consul。
在 docker 主機 host1(172.20.10.2)和 host2(172.20.10.7)上實踐各種跨主機網路方案,在 172.20.10.2 上部署支援的元件,比如 Consul。
第一步:啟動路由轉發功能
兩臺主機上面都需要開啟
[root@ken3 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward
第二步:執行consul
最簡單的方式是以容器方式執行 Consul:
[root@ken1 ~]# docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
第三步:瀏覽器訪問
容器啟動後,可以通過 http://172.20.10.2:8500 訪問 Consul。
第四步:修改docker啟動檔案
接下來修改 host1 和 host2 的 docker daemon 的配置檔案/usr/lib/systemd/system/docker.service
[Service] Type=notify # the default is not to use systemd for cgroups because the delegate issues still # exists and systemd currently does not support the cgroup feature set required # for containers run by docker ExecStart=/usr/bin/dockerd -H unix:// --cluster-store=consul://172.20.10.2:8500 --cluster-advertise=eth0:2376 ...
--cluster-store
指定 consul 的地址。
--cluster-advertise
告知 consul 自己的連線地址(eth0即為網絡卡名,固定格式)
重啟 docker daemon。
[root@ken1 ~]# systemctl daemon-reload [root@ken1 ~]# systemctl restart docker
重啟consul
[root@ken1 ~]# docker rm $(docker ps -aq) [root@ken1 ~]# docker run -d -p 8500:8500 -h consul --name consul progrium/consul -server -bootstrap
第五步:瀏覽器檢視
可以發現兩個主機已經自動註冊上去了
建立overlay網路
在host1中建立網路ov_ken
[root@ken1 ~]# docker network create -d overlay ov_ken 25979f1d44c12362f3866295995756984468060c10479288835d64588f27fa3b [root@ken1 ~]# docker network ls NETWORK IDNAMEDRIVERSCOPE e36545bfeb92bridgebridgelocal 43b0997b8ce5hosthostlocal 36d9a3277b19nonenulllocal 25979f1d44c1ov_kenoverlayglobal
注意到 ov_ken
的 SCOPE 為 global,而其他網路為 local。在 host2 上檢視存在的網路:
host2 上也能看到 ov_ken。這是因為建立 ov_ken 時 host1 將 overlay 網路資訊存入了 consul,host2 從 consul 讀取到了新網路的資料。之後 ov_ken 的任何變化都會同步到 host1 和 host2。
docker network inspect
檢視 ov_ken 的詳細資訊:
docker 自動為 ov_ken分配的 IP 空間為 10.0.0.0/24。
在overlay中執行容器
行一個 busybox 容器並連線到 ov_ken:
[root@ken1 ~]# docker run -itd --name b1 --network ov_ken busybox fc6454145e12c1c1a494914e3c71d4a9c7c7da0d6ed888e4b6d2afe80379e000
訪問外網測試
可以發現容器訪問外網是沒有問題的
外網想要訪問主機可以通過埠對映
[root@ken1 ~]# docker exec b1 ping -c 2 www.baidu.com PING www.baidu.com (61.135.169.125): 56 data bytes 64 bytes from 61.135.169.125: seq=0 ttl=54 time=25.144 ms 64 bytes from 61.135.169.125: seq=1 ttl=54 time=24.358 ms --- www.baidu.com ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 24.358/24.751/25.144 ms
跨主機連通
在 host2 中執行容器 b2
[root@ken3 ~]# docker run -itd --name b2 --network ov_ken busybox
檢視b2的網路
b2的ip為10.0.0.3
[root@ken3 ~]# docker exec b2 ip r default via 172.18.0.1 dev eth1 10.0.0.0/24 dev eth0 scope linksrc 10.0.0.3 172.18.0.0/16 dev eth1 scope linksrc 172.18.0.2
測試b1能否ping通b2
[root@ken1 ~]# docker exec b1 ping -c 2 10.0.0.3 PING 10.0.0.3 (10.0.0.3): 56 data bytes 64 bytes from 10.0.0.3: seq=0 ttl=64 time=10.344 ms 64 bytes from 10.0.0.3: seq=1 ttl=64 time=1.694 ms --- 10.0.0.3 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 1.694/6.019/10.344 ms [root@ken1 ~]# docker exec b1 ping -c 2 b2 PING b2 (10.0.0.3): 56 data bytes 64 bytes from 10.0.0.3: seq=0 ttl=64 time=2.916 ms 64 bytes from 10.0.0.3: seq=1 ttl=64 time=1.950 ms --- b2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 1.950/2.433/2.916 ms
可見 overlay 網路中的容器可以直接通訊,同時 docker 也實現了 DNS 服務。
overlay網路隔離
不同的 overlay 網路是相互隔離的。我們建立第二個 overlay 網路 ov_ken2 並執行容器 b
[root@ken1 ~]# docker network create -d overlay ov_ken2 2008b1f950566f105a567ea422ef2269b1db226de58b2d8d8350a91106542d27 [root@ken1 ~]# docker run -itd --name b3 --network ov_ken2 busybox 9f6b4166169ebe5993f8533c57dbf0089fe539a09607d94d3d9442990c8393ea
檢視b3分配到的IP
可以發現是10.0.1.2
[root@ken1 ~]# docker exec b3 ip r default via 172.18.0.1 dev eth1 10.0.1.0/24 dev eth0 scope linksrc 10.0.1.2 172.18.0.0/16 dev eth1 scope linksrc 172.18.0.3
現在嘗試ping b2
[root@ken1 ~]# docker exec b3 ping -c 2 10.0.0.3 PING 10.0.0.3 (10.0.0.3): 56 data bytes --- 10.0.0.3 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss
ping 失敗,可見不同 overlay 網路之間是隔離的。
如果要實現 b3 與 b2 通訊,可以將 b3 也連線到 ov_ken。
[root@ken1 ~]# docker network connect ov_ken b3 [root@ken1 ~]# docker exec b3 ip r default via 172.18.0.1 dev eth1 10.0.0.0/24 dev eth2 scope linksrc 10.0.0.4 10.0.1.0/24 dev eth0 scope linksrc 10.0.1.2 172.18.0.0/16 dev eth1 scope linksrc 172.18.0.3
可以發現現在的b3有了一個eth2的網絡卡,ip地址為10.0.0.4
現在再來測試一下b3能否ping通b2
[root@ken1 ~]# docker exec b3 ping -c 2 10.0.0.3 PING 10.0.0.3 (10.0.0.3): 56 data bytes 64 bytes from 10.0.0.3: seq=0 ttl=64 time=7.145 ms 64 bytes from 10.0.0.3: seq=1 ttl=64 time=2.769 ms --- 10.0.0.3 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 2.769/4.957/7.145 ms
可以發現現在可以ping通了
weave網路
weave 不依賴分散式資料庫(例如 etcd 和 consul)交換網路資訊,每個主機上只需執行 weave 元件就能建立起跨主機容器網路。接下來在 host1 和 host2 上部署 weave 並實踐 weave 的各項特性。
安裝部署weave
weave 安裝非常簡單,在 host1 和 host2 上執行如下命令:
[root@ken1 ~]# curl -L git.io/weave -o /usr/local/bin/weave [root@ken1 ~]# chmod a+x /usr/local/bin/weave
host1中啟動weave
在 host1 中執行 weave launch
命令,啟動 weave 相關服務。weave 的所有元件都是以容器方式執行的,weave 會從 docker hub 下載最新的 image 並啟動容器。
[root@ken1 ~]# weave launch
檢視啟動的容器
[root@ken1 ~]# docker ps CONTAINER IDIMAGECOMMANDCREATEDSTATUSPORTSNAMES 7a59dcccd908weaveworks/weave:2.5.1"/home/weave/weaver …"37 seconds agoRestarting (1) 36 seconds agoweave
weave 運行了一個容器:
weave
是主程式,負責建立 weave 網路,收發資料 ,提供 DNS 服務等。
host1中啟動容器
[root@ken ~]# eval $(weave env) [root@ken ~]# docker run --name b1 --rm -itd busybox e04f798321072542450ca800601e980d206e00e8850b1b1ce16f4cba8ce94a32
首先執行 eval $(weave env)
很重要,其作用是將後續的 docker 命令發給 weave proxy 處理。如果要恢復之前的環境,可執行 eval $(weave env --restore)
。
檢視一下當前容器 bbox1 的網路配置:
b1 有兩個網路介面 eth0 和 ethwe,其中 eth0 連線的是預設 bridge 網路,即網橋 docker0。
分配的 IP 10.32.0.1/12 ethwe 與 weave 相關
再執行一個容器 b2。
[root@ken ~]# docker run --name b2 --rm -itd busybox abf55e9dead051e0e87afd524243fbb7c3a6985042d0d924a829a91399c76ade
測試b1與b2的連通性(相同主機host!)
可以發現b1與b2不僅可以互相ping通,還可以解析
[root@ken ~]# docker exec b1 ping -c 2 b2 PING b2 (10.32.0.2): 56 data bytes 64 bytes from 10.32.0.2: seq=0 ttl=64 time=0.141 ms 64 bytes from 10.32.0.2: seq=1 ttl=64 time=0.282 ms --- b2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 0.141/0.211/0.282 ms
weave跨主機通訊
第一步:首先在host2 執行如下命令
[root@ken3 ~]# weave launch 172.20.10.2 e69a5bec56eb8d5471b139ce2c3080f2681e44c7bf582ef798c017d83107e3ac
這裡必須指定 host1 的 IP 172.20.10.2 ,這樣 host1 和 host2 才能加入到同一個 weave 網路。
第二步:開啟路由轉發功能
echo "1">/proc/sys/net/ipv4/ip_forward
第三步:啟動容器
[root@ken3 ~]# eval $(weave env) [root@ken3 ~]# docker run --name b3 --rm -itd busybox 4c86439dd59d545eb73e796709872cd51e4953503e63c2a0ff4549b2eb3ce8fa
第四步:測試容器連線性
可以發現主機host2上執行的b3容器可以與host1主機上面執行的b1和b2容器進行通訊,而且可以解壓主機名。
[root@ken3 ~]# docker exec b3 ping -c 2 b1 PING b1 (10.32.0.1): 56 data bytes 64 bytes from 10.32.0.1: seq=0 ttl=64 time=7.157 ms 64 bytes from 10.32.0.1: seq=1 ttl=64 time=1.021 ms --- b1 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 1.021/4.089/7.157 ms [root@ken3 ~]# docker exec b3 ping -c 2 b2 PING b2 (10.32.0.2): 56 data bytes 64 bytes from 10.32.0.2: seq=0 ttl=64 time=8.116 ms 64 bytes from 10.32.0.2: seq=1 ttl=64 time=1.960 ms --- b2 ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max = 1.960/5.038/8.116 ms
weave網路隔離
預設配置下,weave 使用一個大 subnet(例如 10.32.0.0/12),所有主機的容器都從這個地址空間中分配 IP,因為同屬一個 subnet,容器可以直接通訊。如果要實現網路隔離,可以通過環境變數 WEAVE_CIDR
為容器分配不同 subnet 的 IP,舉例如下:
[root@ken3 ~]# docker run -e WEAVE_CIDR=net:10.32.2.0/24 --rm -itd busybox 98bc93412af210e08b4be7a9456e40749ca4a0672f3ebbc5a5f616ab0b4d3b50
這裡 WEAVE_CIDR=net:10.32.2.0/24
的作用是使容器分配到 IP 10.32.2.2
。由於 10.32.0.0/12 與 10.32.2.0/24 位於不同的 subnet,所以無法 ping 到 b2。
[root@ken3 ~]# docker exec 98bc93412af ping -c 2 b2 PING b2 (10.32.0.2): 56 data bytes --- b2 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss
除了 subnet,我們還可以直接為容器分配特定的 IP:
[root@ken3 ~]# docker run -e WEAVE_CIDR=ip:10.32.6.6/24 -it busybox / # ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 36: eth0@if37: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff inet 172.17.0.4/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever 38: ethwe@if39: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1376 qdisc noqueue link/ether ae:e0:cd:41:ac:f5 brd ff:ff:ff:ff:ff:ff inet 10.32.6.6/24 brd 10.32.6.255 scope global ethwe valid_lft forever preferred_lft forever / # ping -c 2 b2 PING b2 (10.32.0.2): 56 data bytes --- b2 ping statistics --- 2 packets transmitted, 0 packets received, 100% packet loss
weave與外網的連通性
weave 是一個私有的 VxLAN 網路(容器可以訪問外網),預設與外部網路隔離。外部網路如何才能訪問到 weave 中的容器呢?
答案是:
-
首先將主機加入到 weave 網路。
-
然後把主機當作訪問 weave 網路的閘道器。
第一步:要將主機加入到 weave,執行 weave expose
。
[root@ken3 ~]# weave expose 10.32.2.129
第二步:檢視IP
這個 IP 10.32.2.129
會被配置到 host2 的 weave 網橋上。
第三步:測試連通性
ping同一主機的b3
[root@ken3 ~]# ping -c 2 10.44.0.0 PING 10.44.0.0 (10.44.0.0) 56(84) bytes of data. 64 bytes from 10.44.0.0: icmp_seq=1 ttl=64 time=0.327 ms 64 bytes from 10.44.0.0: icmp_seq=2 ttl=64 time=0.068 ms --- 10.44.0.0 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 999ms rtt min/avg/max/mdev = 0.068/0.197/0.327/0.130 ms
ping host1中的b1
[root@ken3 ~]# ping -c 2 10.32.0.1 PING 10.32.0.1 (10.32.0.1) 56(84) bytes of data. 64 bytes from 10.32.0.1: icmp_seq=1 ttl=64 time=28.4 ms 64 bytes from 10.32.0.1: icmp_seq=2 ttl=64 time=0.975 ms --- 10.32.0.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1002ms rtt min/avg/max/mdev = 0.975/14.708/28.442/13.734 ms
接下來要讓其他非 weave 主機訪問到 bbox1 和 bbox3,只需將閘道器指向 host1。例如在 172.20.10.9上新增如下路由:
[root@host2 ~]# ip route add 10.32.0.0/12 via 172.20.10.2 [root@host2 ~]# ping -c 2 10.32.0.1 PING 10.32.0.1 (10.32.0.1) 56(84) bytes of data. 64 bytes from 10.32.0.1: icmp_seq=1 ttl=63 time=1.45 ms 64 bytes from 10.32.0.1: icmp_seq=2 ttl=63 time=2.25 ms --- 10.32.0.1 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1002ms rtt min/avg/max/mdev = 1.450/1.852/2.254/0.402 ms
10.32.0.0/12 是 weave 網路使用的預設 subnet,如果此地址空間與現有 IP 衝突,可以通過 --ipalloc-range
分配特定的 subnet。
weave launch --ipalloc-range 10.2.0.0/16
不過請確保所有 host 都使用相同的 subnet。