1. 程式人生 > 實用技巧 >Docker系列04—跨主機網路方案(overlay/weave)

Docker系列04—跨主機網路方案(overlay/weave)

在前面詳細講解了幾種網路模式:none,host,bridge,container。他們解決了單個主機間的容器的通訊問題,並不能實現多個主機容器之間的通訊。

跨主機網路方案包括兩大類:

1,docker原生的:overlay和macvlan

2,第三方方案:flannel、weave和calico

overlay

Docker overlay網路需要一個key-value資料庫用於儲存網路狀態資訊,包括Network、Endpoint、IP等。

consul、Etcd、Zookeeper都是Docker支援的key-value軟體,這裡我們使用consul。

在docker主機docker01(10.0.0.11)和docker02(10.0.0.12)上實踐各種跨主機網路方案,在10.0.0.11上部署支援的元件,比如consul。

第一步:啟動路由轉發功能

【兩臺主機都需開啟】

[root@docker01 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward
[root@docker02 ~]# echo "1" > /proc/sys/net/ipv4/ip_forward

第二步:執行consul

以容器的方式執行consul

[root@docker01 ~]# systemctl restart docker
[root@docker01 ~]# systemctl enable docker
[root@docker01 ~]# docker pull progrium/consul
Using default tag: latest
latest: Pulling from progrium/consul

[root@docker01 ~]# docker run -d -p 8500:8500 -h consul --name consul --restart=always progrium/consul -server -bootstrap
### 其中 -h 為指定容器內部的主機名;--restart=always 為docker啟動時,此容器自動啟動;-server -bootstrap 表示當在群集中,加上這兩個選項可以使其以master的身份出現

[root@docker01 ~]# netstat -lntp | grep 8500
tcp6       0      0 :::8500                 :::*                    LISTEN      1576/docker-proxy

  

第三步:瀏覽器訪問

通過ip+port的方式訪問

第四步:修改docker啟動檔案

需要修改的是docker01和docker02的docker daemon 的配置檔案。

【注】在這裡我們使用的是兩臺。如果是3臺,可以為3臺都設定:表示這3臺準備跨主機;也可以將第一臺設定為只存放consul,2,3臺修改配置檔案即可:表示後兩臺準備跨主機。

【注】只修改[Service]內容即可

[root@docker01 ~]# cat /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:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://10.0.0.11:8500 --cluster-advertise=eth0:2376
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
...

### 各項解釋如下
# /var/run/docker.sock 表示Docker的一個程式設計介面;
# '-H tcp://0.0.0.0:2376' 表示使用本機的2376/tcp埠;
# '--cluster-store=consul://10.0.0.11:8500' 表示運行了consul的伺服器IP和埠
# '--cluster-advertise=eth0:2376' 表示從本機的eth0網絡卡通過2376埠收集網路資訊,也有可能是ens33。

  

[root@docker02 ~]# cat /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:///var/run/docker.sock -H tcp://0.0.0.0:2376 --cluster-store=consul://10.0.0.11:8500 --cluster-advertise=eth0:2376
# ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutSec=0
RestartSec=2
Restart=always
...

 

重新載入docker daemon,修改了檔案的服務都需要重啟

[root@docker01 ~]# systemctl daemon-reload
[root@docker01 ~]# systemctl restart docker

這裡注意,如果consul容器沒有設定為自啟,那麼需要手動啟動

[root@docker02 ~]# systemctl daemon-reload
[root@docker02 ~]# systemctl restart docker

第五步:瀏覽器檢視

這時發現兩個主機已經註冊上去了

第六步:建立overlay網路

在docker01上建立網路ov_ken

[root@docker01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c8d69c4c3ffe        bridge              bridge              local
f5d3339712b4        host                host                local
93359dad0336        none                null                local

[root@docker01 ~]# docker network create -d overlay ov_ken

[root@docker01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c8d69c4c3ffe        bridge              bridge              local
f5d3339712b4        host                host                local
93359dad0336        none                null                local
70c2c8b47ead        ov_ken              overlay             global

### 這個時候docker02上不用新增就會自動新增
[root@docker02 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
7c9560f3b566        bridge              bridge              local
e76394dcf8f8        host                host                local
4cdde3f7dce2        none                null                local
70c2c8b47ead        ov_ken              overlay             global
### 因為建立ov_ken時docker01將overlay網路資訊存入了consul,docker02從consul讀取了新網路的資料。

 

檢視網路資訊

[root@docker01 ~]# docker network inspect ov_ken
[
    {
        "Name": "ov_ken",
        "Id": "70c2c8b47ead8af423a6b562aba42f1106454b58577c27cf47143a9eacdb419a",
        "Created": "2020-04-13T11:47:08.079686153+08:00",
        "Scope": "global",
        "Driver": "overlay",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "10.0.0.0/24",
                    "Gateway": "10.0.0.1"
                }
            ]
        },
### 由此可以看出docker自動為ov_ken分配的ip地址空間為10.0.0.0/24
 

 

在overlay網路中執行容器

執行一個busybox容器並使用overlay網路

[root@docker01 ~]# docker run -d -it --name busybox --network ov_ken busybox:latest
3492931078a8d2cf2a7e77b7a8518c3f89f64c0b803a79ffc9742965581d96fa

6.1 跨主機連通

在docker02上執行新的容器

[root@docker02 ~]# docker run -it -d --name busybox_02 --network ov_ken busybox:latest
53e708b68a31d5f08bce6f949426e64ce333e4ee9f28396271b2a6eb3daad182

檢視容器的網路

[root@docker02 ~]# docker exec busybox_02 ip r
default via 172.18.0.1 dev eth1 
10.0.0.0/24 dev eth0 scope link  src 10.0.0.3 
172.18.0.0/16 dev eth1 scope link  src 172.18.0.2

測試使用docker01上的容器ping docker02上的容器

[root@docker01 ~]# docker exec busybox ip r
default via 172.18.0.1 dev eth1 
10.0.0.0/24 dev eth0 scope link  src 10.0.0.2 
172.18.0.0/16 dev eth1 scope link  src 172.18.0.2 

[root@docker01 ~]# docker exec busybox 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=3.657 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.351 ms
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.351/2.004/3.657 ms
 

 

至此:overlay容器是可以直接通訊,同時docker也實現了DNS服務。

6.2 overlay網路隔離

不同的overlay網路是相互隔離的。我們建立第二個overlay網路ov_ken2並執行容器

[root@docker01 ~]# docker network create -d overlay ov_ken2
0dd70337a3f1504c9d24891c9e37d74af35abcad0ce3751ac0efa5ad138cb12c

[root@docker01 ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
c8d69c4c3ffe        bridge              bridge              local
2436e5e8c848        docker_gwbridge     bridge              local
f5d3339712b4        host                host                local
93359dad0336        none                null                local
70c2c8b47ead        ov_ken              overlay             global
0dd70337a3f1        ov_ken2             overlay             global

[root@docker01 ~]# docker run -d -it --name busybox_03 --network ov_ken2 busybox:latest
a5963fd6a9b863613269f773069fa99630fc88d7af49a3b355e78c9060858699

[root@docker01 ~]# docker exec busybox_03 ip r
default via 172.18.0.1 dev eth1 
10.0.1.0/24 dev eth0 scope link  src 10.0.1.2 
172.18.0.0/16 dev eth1 scope link  src 172.18.0.3
### 在這裡我們能看到docker給第二個overlay分配的ip地址為10.0.1.0/24

[root@docker01 ~]# docker exec busybox_03 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
### 在這裡我們發現ov_ken和ov_ken2並不互通

  

如果要實現busybox_03和busybox_02的互通,可以將busybox_03也連線到ov_ken網路上

[root@docker01 ~]# docker network connect ov_ken busybox_03
### 意思為,將busybox_03新增到ov_ken網路

[root@docker01 ~]# docker exec busybox_03 ip r
default via 172.18.0.1 dev eth1 
10.0.0.0/24 dev eth2 scope link  src 10.0.0.4 
10.0.1.0/24 dev eth0 scope link  src 10.0.1.2 
172.18.0.0/16 dev eth1 scope link  src 172.18.0.3 
###  這個時候會發現busybox_03會被新增一個新的ov_ken的網段IP

[root@docker01 ~]# docker exec busybox_03 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=6.571 ms
64 bytes from 10.0.0.3: seq=1 ttl=64 time=0.411 ms
--- 10.0.0.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.411/3.491/6.571 ms

weave

weave不依賴分散式資料庫(例如etcd和consul)交換網路資訊,每個主機上只需要執行weave元件就能建立起跨主機容器網路。接下來在docker01和docker02上部署weave並實踐weave的各項特性

一、安裝部署weave

weave安裝非常簡單,在docker01和docker02上執行如下命令:

[root@docker01 ~]# curl -L git.io/weave -o /usr/local/bin/weave
[root@docker01 ~]# chmod a+x /usr/local/bin/weave
 


[root@docker02 ~]# curl -L git.io/weave -o /usr/local/bin/weave
[root@docker02 ~]# chmod a+x /usr/local/bin/weave
 

在docker01上啟動weave

[root@docker01 ~]# weave launch

注:在執行weave launch命令,啟動weave相關服務。weave所有的元件都是以容器的方式執行的,會自動從docker hub上獲取最新的image並啟動容器

檢視啟動的容器

[root@docker01 ~]# docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS              PORTS  NAMES
e089485df46f        weaveworks/weave:2.6.2   "/home/weave/weaver …"   55 seconds ago      Up 54 seconds              weave

weave運行了一個容器:

weave是主程式,負責建立weave網路,收發資料,提供DNS服務等

在docker01中啟動容器

[root@docker01 ~]# eval $(weave env)
[root@docker01 ~]# docker run -d -it --name busybox_01 --rm busybox:latest
a1a4f0931a65b36067f8d27e6474fee584d003ac302e9c7ac4e517f48b0d46a2

注意:在這裡因為是測試,用到了 --rm :關閉即刪除,刪除,刪除 !!

首先執行 eval $(weave env) 很重要,其作用是將後續的docker命令傳送給weave proxy處理,如果要恢復之前的環境,可執行eval $(weave env --restore)。

檢視當前容器busybox_01的網路配置

[root@docker01 ~]# docker exec busybox_01 ip r
default via 172.17.0.1 dev eth0 
10.32.0.0/12 dev ethwe scope link  src 10.32.0.1 
172.17.0.0/16 dev eth0 scope link  src 172.17.0.2 
224.0.0.0/4 dev ethwe scope link 

### 由此可以看出,docker給其分配的地址為10.32.0.0/12網段,並且IP地址為10.32.0.1
### 而且busybox_01有兩個網路介面eth0和ethwe,其中eth0是預設連線的bridge網路,即網橋docker0。分配的IP 10.32.0.1/12 ethwe與weave相關

 

在當前主機上再執行一個容器

[root@docker01 ~]# docker run -d -it --name busybox_02 --rm busybox:latest
88f208a2ca486eccc346ed7239f44836587796ce7898f48b65e162bfebe522e6

[root@docker01 ~]# docker exec busybox_02 ip r
default via 172.17.0.1 dev eth0 
10.32.0.0/12 dev ethwe scope link  src 10.32.0.2 
172.17.0.0/16 dev eth0 scope link  src 172.17.0.3
224.0.0.0/4 dev ethwe scope link 
 

測試同一個主機上的busybox_01和busybox_02的連通性

[root@docker01 ~]# docker exec busybox_01 ping -c 2 busybox_02
PING busybox_02 (10.32.0.2): 56 data bytes
64 bytes from 10.32.0.2: seq=0 ttl=64 time=0.051 ms
64 bytes from 10.32.0.2: seq=1 ttl=64 time=0.050 ms

--- busybox_02 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.050/0.050/0.051 ms

### 在這裡是可以連通的,並且還可以解析

二、weave跨主機通訊

第一步:再docker02上執行以下命令

[root@docker02 ~]# weave launch 10.0.0.11
## 格式 weave launch [docker01的ip地址]

這裡必須指定docker01的ip地址,這樣docker01和docker02才能加入到同一個weave網路。

第二步:開啟路由轉發功能

[root@docker01 ~]# echo "1">/proc/sys/net/ipv4/ip_forward
[root@docker02 ~]# echo "1">/proc/sys/net/ipv4/ip_forward

第三步:啟動容器

[root@docker02 ~]# docker run -d -it --name busybox_03 --rm busybox:latest
82503c97ee984d5a330f635eeca825edc795c7ef96a8fc592da9dc8598764594

第四步:測試連通性

[root@docker02 ~]# docker exec busybox_03 ping -c 2 busybox_02
PING busybox_02 (10.32.0.2): 56 data bytes
64 bytes from 10.32.0.2: seq=0 ttl=64 time=1.477 ms
64 bytes from 10.32.0.2: seq=1 ttl=64 time=1.187 ms

--- busybox_02 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 1.187/1.332/1.477 ms

### 可以發現主機docker02上執行的容器可以與docker01上的容器通訊,而且可以解析主機名

三、weave網路隔離

預設配置下,weave使用一個大subnet(例如10.32.0.0/12),所有的主機的容器都是從這個地址空間中分配IP,因為同屬一個subnet,容器可以直接通訊。如果要實現網路隔離,可以通過環境變數WEAVE_CIDR為容器分配不同的subnet的IP,舉例如下:

[root@docker02 ~]# docker run -d -it -e WEAVE_CIDR=net:10.32.2.0/24 --name busybox_04 --rm busybox:latest
d3a4430bbc111c9f7eca1ab9c4b6f432f63d9e45d66ea0d0d66b3dfecfa75eb6

在這裡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到busybox_02。

[root@docker02 ~]# docker exec busybox_04 ping -c 2 busybox_02
PING busybox_02 (10.32.0.2): 56 data bytes
--- busybox_02 ping statistics ---
2 packets transmitted, 0 packets received, 100% packet loss

當然也無法ping同同主機上的busybox_03

除了subnet,我們還可以直接為容器分配特定的ip:

[root@docker02 ~]# docker run -d -it -e WEAVE_CIDR=ip:10.32.6.6/24 --name busybox_05 busybox:latest
b2eccb69e37e5da8558237163103f050a3efc118cf71bf11c62c68b572e2b8a6
[root@docker02 ~]# docker exec busybox_05 ip r
default via 172.17.0.1 dev eth0 
10.32.6.0/24 dev ethwe scope link  src 10.32.6.6 
172.17.0.0/16 dev eth0 scope link  src 172.17.0.4 
224.0.0.0/4 dev ethwe scope link 

四、weave與外網的連通性

weave是一個私有的VLAN網路(容器可以訪問外網),預設與外部網路隔離。外部網路如何才能訪問到weave中的容器呢?

答案:

  1. 首先將主機加入到weave網路。

  2. 然後把主機當作訪問的閘道器。

第一步:要將主機加入到weave,執行weave expose。

[root@docker02 ~]# weave expose
10.32.2.129

第二步:檢視ip

這個10.32.2.129會被配置到host2的weave網橋上。

[root@docker02 ~]# ip a
...
13: weave: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1376 qdisc noqueue state UP qlen 1000
    link/ether c6:77:0c:f6:e2:29 brd ff:ff:ff:ff:ff:ff
    inet 10.32.2.129/12 brd 10.47.255.255 scope global weave
       valid_lft forever preferred_lft forever
    inet6 fe80::c477:cff:fef6:e229/64 scope link 
       valid_lft forever preferred_lft forever

第三步:測試連通性

ping同一主機的busybox_03

[root@docker02 ~]# docker exec busybox_03 ip r
default via 172.17.0.1 dev eth0 
10.32.0.0/12 dev ethwe scope link  src 10.44.0.0 
172.17.0.0/16 dev eth0 scope link  src 172.17.0.2 
224.0.0.0/4 dev ethwe scope link 


[root@docker02 ~]# 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.123 ms
64 bytes from 10.44.0.0: icmp_seq=2 ttl=64 time=0.048 ms
--- 10.44.0.0 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.048/0.085/0.123/0.038 ms

ping docker01上的busybox_01

[root@docker01 ~]# docker exec busybox_01 ip r
default via 172.17.0.1 dev eth0 
10.32.0.0/12 dev ethwe scope link  src 10.32.0.1 
172.17.0.0/16 dev eth0 scope link  src 172.17.0.2 
224.0.0.0/4 dev ethwe scope link 

[root@docker02 ~]# 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=2.16 ms
64 bytes from 10.32.0.1: icmp_seq=2 ttl=64 time=0.337 ms

--- 10.32.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.337/1.252/2.168/0.916 ms
 

接下來要讓其他非weave主機訪問到busybox_01和busybox_03,只需要將閘道器指向docker01。例如在新的主機docker03上新增如下路由:

[root@docker03 ~]# ip route add 10.32.0.0/12 via 10.0.0.11

[root@docker03 ~]# 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

【注意】如果出現以下情況

[root@docker02 ~]# docker ps
Cannot connect to the Docker daemon at unix:///var/run/weave/weave.sock. Is the docker daemon running?

需要執行

[root@docker02 ~]# eval $(weave env --restore)