前面介绍了Docker管理工具-Swarm部署记录,下面重点说下Swarm基于多主机容器通信的覆盖网络

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
在Docker版本1.12之后swarm模式原生支持覆盖网络(overlay networks),可以先创建一个覆盖网络,然后启动容器的时候启用这个覆盖网络,
这样只要是这个覆盖网络内的容器,不管在不在同一个宿主机上都能相互通信,即跨主机通信!不同覆盖网络内的容器组之间是相互隔离的(相互 ping 不通)。
   
swarm模式的覆盖网络包括以下功能:
1)可以附加多个服务到同一个网络。
2)默认情况下,service discovery为每个swarm服务分配一个虚拟IP地址(vip)和DNS名称,使得在同一个网络中容器之间可以使用服务名称为互相连接。
3)可以配置使用DNS轮循而不使用VIP
4)为了可以使用swarm的覆盖网络,在启用swarm模式之间你需要在swarm节点之间开放以下端口:
5)TCP /UDP 端口7946 – 用于容器网络发现
6)UDP端口4789 – 用于容器覆盖网络
   
实例如下:
-----------在Swarm集群中创建overlay网络------------
[root@manager-node ~] # docker network create --driver overlay --opt encrypted --subnet 10.10.110.0/24 ngx_net
   
参数解释:
–opt encrypted  默认情况下swarm中的节点通信是加密的。在不同节点的容器之间,可选的–opt encrypted参数能在它们的vxlan流量启用附加的加密层。
--subnet 命令行参数指定overlay网络使用的子网网段。当不指定一个子网时,swarm管理器自动选择一个子网并分配给网络。
   
[root@manager-node ~] # docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
ca221724531c        bridge              bridge               local               
10d1451ecc8d        docker_gwbridge     bridge               local               
5764ade8774b        host                host                 local               
50kipkihuwxy        ingress             overlay             swarm               
cz4b4ht5refq        ngx_net             overlay             swarm               
f2af952cd27a        none                null                 local 
   
由上可知,Swarm当中拥有2套覆盖网络。其中 "ngx_net" 网络正是我们在部署容器时所创建的成果。而 "ingress" 覆盖网络则为默认提供。
Swarm 管理节点会利用 ingress 负载均衡以将服务公布至集群之外。
在将服务连接到这个创建的网络之前,网络覆盖到manager节点。上面输出的SCOPE为 swarm 表示将服务部署到Swarm时可以使用此网络。
在将服务连接到这个网络后,Swarm只将该网络扩展到特定的worker节点,这个worker节点被swarm调度器分配了运行服务的任务。
在那些没有运行该服务任务的worker节点上,网络并不扩展到该节点。
   
------------------将服务连接到overlay网络-------------------
[root@manager-node ~] # docker service create --replicas 5 --network ngx_net --name my-test -p 80:80 nginx
   
上面名为 "my-test" 的服务启动了3个task,用于运行每个任务的容器都可以彼此通过overlay网络进行通信。Swarm集群将网络扩展到所有任务处于Running状态的节点上。
[root@manager-node ~] # docker service ls
ID            NAME     REPLICAS  IMAGE  COMMAND
9vgixbn6t2ju  my- test   5 /5        nginx 
   
在manager-node节点上,通过下面的命令查看哪些节点有处于running状态的任务:
[root@manager-node ~] # docker service ps my-test
ID                         NAME       IMAGE  NODE          DESIRED STATE  CURRENT STATE               ERROR
eh2mo4ei8qah5d9eolx8yapey  my- test .1  nginx  manager-node  Running        Running about a minute ago  
7gg40e57rko5frttqdx9x7ae2  my- test .2  nginx  node2         Running        Running about a minute ago  
1vp1d7cwmn8m6a5k0wtq9xi75  my- test .3  nginx  node1         Running        Running about a minute ago  
03nb3ev2r7sxcilkwizoetx9w  my- test .4  nginx  node1         Running        Running about a minute ago  
a0ibepz0r80mhy4x5cam7i190  my- test .5  nginx  manager-node  Running        Running about a minute ago  
   
可见三个节点都有处于running状态的任务,所以my-network网络扩展到三个节点上。
   
可以查询某个节点上关于my-network的详细信息:
[root@manager-node ~] # docker network inspect ngx_net
[
     {
         "Name" "ngx_net" ,
         "Id" "cz4b4ht5refqxelx0mm871ec6" ,
         "Scope" "swarm" ,
         "Driver" "overlay" ,
         "EnableIPv6" false ,
         "IPAM" : {
             "Driver" "default" ,
             "Options" : null,
             "Config" : [
                 {
                     "Subnet" "10.10.110.0/24" ,
                     "Gateway" "10.10.110.1"
                 }
             ]
         },
         "Internal" false ,
         "Containers" : {
             "aa954b709a30be6eaf48e06a6c7c4a0642b75d76e121707df6fc1479d99c7b22" : {
                 "Name" "my-test.5.a0ibepz0r80mhy4x5cam7i190" ,
                 "EndpointID" "4841c9c639b876f065d44e0205320f5e990a0678c8d7f4a02e499779af7b5091" ,
                 "MacAddress" "02:42:0a:0a:6e:07" ,
                 "IPv4Address" "10.10.110.7/24" ,
                 "IPv6Address" ""
             },
             "d7633d4108e88a471e1a1b6759b7c43e3fc09ab64de47e29736de7b9c5031963" : {
                 "Name" "my-test.1.eh2mo4ei8qah5d9eolx8yapey" ,
                 "EndpointID" "54e814c87ba0e7df159195067a851a2557ee8010e619db9cc4fdfb3dd6357afa" ,
                 "MacAddress" "02:42:0a:0a:6e:03" ,
                 "IPv4Address" "10.10.110.3/24" ,
                 "IPv6Address" ""
             }
         },
         "Options" : {
             "com.docker.network.driver.overlay.vxlanid_list" "257" ,
             "encrypted" ""
         },
         "Labels" : {}
     }
]
   
从上面的信息可以看出在manager-node节点上,名为my- test 的服务有一个名为my- test .1.eh2mo4ei8qah5d9eolx8yapey和
my- test .5.a0ibepz0r80mhy4x5cam7i190的task连接到名为ngx_net的网络上(另外两个节点node1和node2同样可以用上面命令查看)
[root@node1 ~] # docker network inspect ngx_net
[
     {
         "Name" "ngx_net" ,
         "Id" "cz4b4ht5refqxelx0mm871ec6" ,
         "Scope" "swarm" ,
         "Driver" "overlay" ,
         "EnableIPv6" false ,
         "IPAM" : {
             "Driver" "default" ,
             "Options" : null,
             "Config" : [
                 {
                     "Subnet" "10.10.110.0/24" ,
                     "Gateway" "10.10.110.1"
                 }
             ]
         },
         "Internal" false ,
         "Containers" : {
             "8dd2171caa337b3c42f35cd6e4590d69cf8edd58ee03463194d0792199415607" : {
                 "Name" "my-test.4.03nb3ev2r7sxcilkwizoetx9w" ,
                 "EndpointID" "dec0675361db102f082798b9e39ed43ca23ae7b795105ae39b90373d42548418" ,
                 "MacAddress" "02:42:0a:0a:6e:06" ,
                 "IPv4Address" "10.10.110.6/24" ,
                 "IPv6Address" ""
             },
             "f29e274d0709403ea97210ff750cdc32054af6cd963ee838bb695e6268264574" : {
                 "Name" "my-test.3.1vp1d7cwmn8m6a5k0wtq9xi75" ,
                 "EndpointID" "e4150c1107a6e52998e3f5417d774d31cdc3d0b24c9aa4305b860cbdf8f78929" ,
                 "MacAddress" "02:42:0a:0a:6e:05" ,
                 "IPv4Address" "10.10.110.5/24" ,
                 "IPv6Address" ""
             }
         },
         "Options" : {
             "com.docker.network.driver.overlay.vxlanid_list" "257" ,
             "encrypted" ""
         },
         "Labels" : {}
     }
]
 
[root@node2 ~] # docker network inspect ngx_net
[
     {
         "Name" "ngx_net" ,
         "Id" "cz4b4ht5refqxelx0mm871ec6" ,
         "Scope" "swarm" ,
         "Driver" "overlay" ,
         "EnableIPv6" false ,
         "IPAM" : {
             "Driver" "default" ,
             "Options" : null,
             "Config" : [
                 {
                     "Subnet" "10.10.110.0/24" ,
                     "Gateway" "10.10.110.1"
                 }
             ]
         },
         "Internal" false ,
         "Containers" : {
             "fddb6518e2bb8c2c2f9f49f95eb3e054ded2a1eff9ec10732a188166f2a60509" : {
                 "Name" "my-test.2.7gg40e57rko5frttqdx9x7ae2" ,
                 "EndpointID" "7263888a54f6211649bef9425aa4acc33ecf838da20d8c93853842e1812f0436" ,
                 "MacAddress" "02:42:0a:0a:6e:04" ,
                 "IPv4Address" "10.10.110.4/24" ,
                 "IPv6Address" ""
             }
         },
         "Options" : {
             "com.docker.network.driver.overlay.vxlanid_list" "257" ,
             "encrypted" ""
         },
         "Labels" : {}
     }
]
   
可以通过查询服务来获得服务的虚拟IP地址,如下:
[root@manager-node ~] # docker service inspect --format='{{json .Endpoint.VirtualIPs}}' my-test
[{ "NetworkID" : "50kipkihuwxy5dqf150z7guad" , "Addr" : "10.255.0.2/16" },{ "NetworkID" : "cz4b4ht5refqxelx0mm871ec6" , "Addr" : "10.10.110.2/24" }]
   
由上结果可知,10.10.110.2其实就是swarm集群内部的vip,整个网络结构如下所示:

Bluemix.png 


加入ngx_net网络的容器彼此之间可以通过IP地址通信,也可以通过名称通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
[root@node2 ~] # docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
fddb6518e2bb        nginx:latest         "nginx -g 'daemon off"    5 minutes ago       Up 5 minutes        80 /tcp               my- test .2.7gg40e57rko5frttqdx9x7ae2
  
[root@node2 ~] # docker exec -ti fddb6518e2bb /bin/bash
root@fddb6518e2bb:/ # apt-get update && apt-get install iproute iputils-ping -y
root@fddb6518e2bb:/ # ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
     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
     inet6 ::1 /128  scope host 
        valid_lft forever preferred_lft forever
246: eth0@if247: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
     link /ether  02:42:0a:ff:00:07 brd ff:ff:ff:ff:ff:ff link-netnsid 0
     inet 10.255.0.7 /16  scope global eth0
        valid_lft forever preferred_lft forever
     inet 10.255.0.2 /32  scope global eth0
        valid_lft forever preferred_lft forever
     inet6 fe80::42:aff:feff:7 /64  scope link 
        valid_lft forever preferred_lft forever
248: eth1@if249: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
     link /ether  02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff link-netnsid 1
     inet 172.18.0.3 /16  scope global eth1
        valid_lft forever preferred_lft forever
     inet6 fe80::42:acff:fe12:3 /64  scope link 
        valid_lft forever preferred_lft forever
251: eth2@if252: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1424 qdisc noqueue state UP group default 
     link /ether  02:42:0a:0a:6e:04 brd ff:ff:ff:ff:ff:ff link-netnsid 2
     inet 10.10.110.4 /24  scope global eth2
        valid_lft forever preferred_lft forever
     inet 10.10.110.2 /32  scope global eth2
        valid_lft forever preferred_lft forever
     inet6 fe80::42:aff:fe0a:6e04 /64  scope link 
        valid_lft forever preferred_lft forever
  
root@fddb6518e2bb:/ # ping 10.10.110.3
PING 10.10.110.3 (10.10.110.3) 56(84) bytes of data.
64 bytes from 10.10.110.3: icmp_seq=1 ttl=64  time =0.437 ms
64 bytes from 10.10.110.3: icmp_seq=2 ttl=64  time =0.310 ms
.....
--- 10.10.110.3  ping  statistics ---
2 packets transmitted, 2 received, 0% packet loss,  time  999ms
rtt min /avg/max/mdev  = 0.310 /0 .373 /0 .437 /0 .066 ms
 
root@fddb6518e2bb:/ # ping 10.10.110.5
PING 10.10.110.5 (10.10.110.5) 56(84) bytes of data.
64 bytes from 10.10.110.5: icmp_seq=1 ttl=64  time =0.438 ms
64 bytes from 10.10.110.5: icmp_seq=2 ttl=64  time =0.329 ms
64 bytes from 10.10.110.5: icmp_seq=3 ttl=64  time =0.359 ms
.....
--- 10.10.110.5  ping  statistics ---
3 packets transmitted, 3 received, 0% packet loss,  time  1999ms
rtt min /avg/max/mdev  = 0.329 /0 .375 /0 .438 /0 .048 ms
  
----------------------------使用swarm模式的服务发现--------------------------
默认情况下,当创建了一个服务并连接到某个网络后,swarm会为该服务分配一个VIP。此VIP根据服务名映射到DNS。在网络上的容器共享该服务的DNS映射,
所以网络上的任意容器可以通过服务名访问服务。
  
在同一overlay网络中,不用通过端口映射来使某个服务可以被其它服务访问。Swarm内部的负载均衡器自动将请求发送到服务的VIP上,然后分发到所有的
active的task上。
  
如下示例:
在同一个网络中添加了一个centos服务,此服务可以通过名称my- test 访问前面创建的nginx服务:
[root@manager-node ~] # docker service create --name my-centos --network ngx_net centos sleep 3000       
  
查询centos运行在哪个节点上(上面创建命令执行后,需要一段时间才能完成这个centos服务的创建)
[root@node2 ~] # docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
ece4ac2e6cc1        centos:latest        "sleep 3000"              42 seconds ago      Up 40 seconds                           my-centos.1.5qwknsxmtr1zhclx9d0f0fx4m
  
登录centos运行的节点(由上可知是node2节点),打开centos的交互shell:
[root@node2 ~] # docker ps
CONTAINER ID        IMAGE                    COMMAND                  CREATED             STATUS            NAMES
e4554490d891        centos:latest             "/bin/bash"              About an hour ago   Up About an hour   my-centos.1.9yk5ie28gwk9mw1h1jovb68ki
  
[root@node2 ~] # docker exec -it my-centos.1.5qwknsxmtr1zhclx9d0f0fx4m /bin/bash
[root@ece4ac2e6cc1 /] # yum install bind-utils -y
[root@ece4ac2e6cc1 /] # nslookup my-test
Server:         127.0.0.11
Address:        127.0.0.11 #53
 
Non-authoritative answer:
Name:   my- test
Address: 10.10.110.2
  
  
从centos容器内部,使用特殊查询 查询DNS,来找到my- test 服务的所有容器的IP地址:
[root@ece4ac2e6cc1 /] # nslookup tasks.my-test
Server:         127.0.0.11
Address:        127.0.0.11 #53
 
Non-authoritative answer:
Name:   tasks.my- test
Address: 10.10.110.3
Name:   tasks.my- test
Address: 10.10.110.7
Name:   tasks.my- test
Address: 10.10.110.5
Name:   tasks.my- test
Address: 10.10.110.4
Name:   tasks.my- test
Address: 10.10.110.6
  
从centos容器内部,通过wget来访问my- test 服务中运行的nginx网页服务器
[root@ece4ac2e6cc1 /] # wget -O- my-test   
--2018-02-08 01:57:26--  http: //my-test/
Resolving my- test  (my- test )... 10.10.110.2
Connecting to my- test  (my- test )|10.10.110.2|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 612 [text /html ]
Saving to:  'STDOUT'
 
  0% [                                                                                                                          ] 0           --.-K /s               <!DOCTYPE html>
<html>
< head >
<title>Welcome to nginx!< /title >
...
  
Swarm的负载均衡器自动将HTTP请求路由到VIP上,然后到一个active的task容器上。它根据round-robin选择算法将后续的请求分发到另一个active的task上。
  
-----------------------------------为服务使用DNS round-robin-----------------------------
在创建服务时,可以配置服务直接使用DNS round-robin而无需使用VIP。这是通过在创建服务时指定 --endpoint-mode dnsrr 命令行参数实现的。
当你想要使用自己的负载均衡器时可以使用这种方式。
  
如下示例(注意:使用DNS round-robin方式创建服务,不能直接在命令里使用-p指定端口)
[root@manager-node ~] # docker service create --replicas 3 --name my-dnsrr-nginx --network ngx_net --endpoint-mode dnsrr nginx
  
[root@manager-node ~] # docker service ps my-dnsrr-nginx
ID                         NAME              IMAGE  NODE          DESIRED STATE  CURRENT STATE          ERROR
8ffi3rs8fg3k4obrvbxg4uwiy  my-dnsrr-nginx.1  nginx  node2         Running        Running 7 seconds ago  
amgmv0kgdopc70z2dr97vn7qq  my-dnsrr-nginx.2  nginx  node1         Running        Running 7 seconds ago  
2p7obdb3h7yicggsbiv5qmvjx  my-dnsrr-nginx.3  nginx  manager-node  Running        Running 7 seconds ago  
  
  
当通过服务名称查询DNS时,DNS服务返回所有任务容器的IP地址:
[root@ece4ac2e6cc1 /] # nslookup my-dnsrr-nginx
Server:         127.0.0.11
Address:        127.0.0.11 #53
 
Non-authoritative answer:
Name:   my-dnsrr-nginx
Address: 10.10.110.12
Name:   my-dnsrr-nginx
Address: 10.10.110.11
Name:   my-dnsrr-nginx
Address: 10.10.110.10
  
需要注意的是:一定要确认VIP的连通性
通常Docker官方推荐使用 dig nslookup 或其它DNS查询工具来查询通过DNS对服务名的访问。因为VIP是逻辑IP, ping 并不是确认VIP连通性的正确的工具。