基于Swarm的多主机容器网络

简介

在Docker1.12版之后,Docker引擎原生支持跨主机的容器网络,但创建跨主机的容器网络时,需要满足一些前提条件:

  • Docker引擎以swarm模式运行
  • 在集群中有一个key-value存储系统

以上两个条件满足任意一个即可以创建跨主机的容器网络。本篇以第一个条件为前提创建跨主机的容器网络。如果想了解基于key-value存储系统的跨主机网络,可以参考官方文档

通过在Swarm模式的Docker引擎创建的跨主机容器网络,并不需要外部的key-value存储系统,这种swarm模式的overlay networks包含以下特性:

  • 可以将多个服务连接到同一个网络中。
  • 默认情况下,容器网络的服务发现机制给swarm集群中的每个服务都分配一个虚拟IP地址和一个DNS条目,所以在同一网络中的容器可以通过服务名称访问服务
  • 可以将服务配置成使用DNS轮询机制而不是VIP机制来进行负载均衡。

创建overlay网络

1
2
3
4
docker network create \
> --driver overlay \
> --subnet 10.0.9.0/24 \
> my-network

--subnet命令行参数指定overlay网络使用的子网网段。创建完成后使用docker network ls查看创建的网络:

1
2
3
docker network ls
NETWORK ID NAME DRIVER SCOPE
5fke0hya379r my-network overlay swarm

将服务连接到overlay网络

1
2
3
4
5
docker service create \
> --replicas 3 \
> --name my-web \
> --network my-network \
> nginx

my-network的详细信息:

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
docker network inspect my-network
[
{
"Name": "my-network",
"Id": "5fke0hya379rbmfhdemevngjx",
"Scope": "swarm",
"Driver": "overlay",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "10.0.9.0/24",
"Gateway": "10.0.9.1"
}
]
},
"Internal": false,
"Containers": {
"f6cb2bc95344e74d2790403ae1072c14cd696247ae62482b7cbf198621b39456": {
"Name": "my-web.3.ag94ocnqubfp4naf6v1utqbog",
"EndpointID": "020adbf9337f08fdf31b1e6282a7e28599e60f93d582ebe101a17f7c4eace2e2",
"MacAddress": "02:42:0a:00:09:05",
"IPv4Address": "10.0.9.5/24",
"IPv6Address": ""
}
},
"Options": {
"com.docker.network.driver.overlay.vxlanid_list": "257"
},
"Labels": {}
}
]

通过查询服务来获得服务的虚拟IP地址:

1
2
3
4
ocker service inspect \
> --format='{{json .Endpoint.VirtualIPs}}' \
> my-web
[{"NetworkID":"5fke0hya379rbmfhdemevngjx","Addr":"10.0.9.2/24"}]

整个网络结构如下图所示:

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

swarm模式的服务发现

默认情况下,当创建了一个服务并连接到某个网络后,swarm会为该服务分配一个VIP。此VIP根据服务名映射到DNS。在网络上的容器共享该服务的DNS映射,所以网络上的任意容器可以通过服务名访问服务

在同一overlay网络中,不用通过端口映射来使某个服务可以被其它服务访问。Swarm内部的负载均衡器自动将请求发送到服务的VIP上,然后分发到所有的active的task上。

下面的实例展示了在同一个网络中添加了一个busybox服务,此服务可以通过名称my-web访问前面创建的nginx服务:

1.在manager节点上,部署一个busybox服务到与my-web服务相同的网络中,也就是my-network中:

1
2
3
4
5
6
docker service create \
> --name my-busybox \
> --network my-network \
> busybox \
> sleep 3000
3rdnz62u2n8d916d5zxbo9lax

2.登录busybox运行的节点,打开busybox的交互shell

1
2
docker exec -it my-busybox.1.1ph2hdtwagafkhd5hkfcx6131 /bin/sh
/ #

3.从busybox容器内部,使用特殊查询查询DNS,来找到my-web服务的所有容器的IP地址

1
2
3
4
5
6
7
# nslookup tasks.my-web
Server: 127.0.0.11
Address 1: 127.0.0.11
Name: tasks.my-web
Address 1: 10.0.9.3 my-web.1.78s6t4si84br75njmc79zux54.my-network
Address 2: 10.0.9.4 my-web.2.99ogxe6mcc3v30e3ugtx53qg7.my-network
Address 3: 10.0.9.5 my-web.3.ag94ocnqubfp4naf6v1utqbog.my-network

Swarm的负载均衡器自动将HTTP请求路由到VIP上,然后到一个activetask容器上。它根据round-robin选择算法将后续的请求分发到另一个activetask上。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器