Update swarm and mesos chapter

This commit is contained in:
Baohua Yang
2017-05-02 23:17:58 +08:00
parent 2568854736
commit 5786333a3b
25 changed files with 1234 additions and 553 deletions

View File

@@ -1,4 +1,6 @@
# Docker Swarm 项目
Docker Swarm 是 Docker 官方编排Orchestration项目之一,负责对 Docker 集群进行管理
# Docker 三剑客之 Docker Swarm
Docker Swarm 是 Docker 官方三剑客项目之一,提供 Docker 容器集群服务,是 Docker 官方对容器云生态进行支持的核心方案
本章将介绍 Swarm 项目情况以及安装和使用。
使用它,用户可以将多个 Docker 主机封装为单个大型的虚拟 Docker 主机,快速打造一套容器云平台。
本章将介绍 Swarm 项目的相关情况,以及如何进行安装和使用。最后还对 Swarm 的服务发现后端、调度器和过滤器等功能进行讲解。

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

BIN
swarm/_images/swarm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

View File

@@ -1,100 +1,108 @@
## Swarm 过滤器
swarm 的调度器(scheduler)在选择节点运行容器的时候支持几种过滤器 (filter)Constraint,Affinity,Port,Dependency,Health
## Swarm 中的过滤器
可以在执行 `swarm manage` 命令的时候通过 `--filter` 选项来设置
Swarm 的调度器可以按照指定调度策略自动分配容器到节点。但有些时候希望能对这些分配加以干预。比如说,让 IO 敏感的容器分配到安装了 SSD 的节点上;让计算敏感的容器分配到 CPU 核数多的机器上;让网络敏感的容器分配到高带宽的机房;让某些容器尽量放同一个节点……
###Constraint Filter
constraint 是一个跟具体节点相关联的键值对可以看做是每个节点的标签这个标签可以在启动docker daemon的时候指定比如
```bash
sudo docker -d --label label_name=label01
这可以通过过滤器filter来实现目前支持 `Constraint``Affinity``Port``Dependency``Health` 等五种过滤器。
### Constraint 过滤器
Constraint 过滤器是绑定到节点的键值对,相当于给节点添加标签。
可在启动 Docker 服务的时候指定,例如指定某个节点颜色为 `red`
```sh
$ sudo docker daemon --label color=red -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
```
可以写在docker的配置文件里面在ubuntu上面`/etc/default/docker`)。
同样的,可以写在 Docker 服务的配置文件里面(以 Ubuntu 14.04 为例,`/etc/default/docker`)。
在本次试验中给083添加标签--label label_name=083,084添加标签--label label_name=084,124添加标签--label label_name=124,
以083为例打开/etc/default/docker文件修改DOCKER_OPTS
```bash
DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock --label label_name=083"
```sh
DOCKER_OPTS="--label color=red -H 0.0.0.0:2375 -H unix:///var/run/docker.sock"
```
使用docker run命令启动容器的时候使`-e constarint:key=value` 的形式,可以指定container运行的节点。
使用 Swarm 启动容器的时候,采`-e constarint:key=value` 的形式,可以过滤选择出匹配条件的节点。
比如我们想在84上面启动一个 redis 容器
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_1 -d -e constraint:label_name==084 redis
fee1b7b9dde13d64690344c1f1a4c3f5556835be46b41b969e4090a083a6382d
```
注意,是**两个**等号,不是一个等号,这一点会经常被忽略。
例如,我们将 `192.168.0.2` 节点打上红色标签,`192.168.0.3` 节点打上绿色标签
接下来再在084这台机器上启动一个redis 容器
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_2 -d -e constraint:label_name==084 redis 4968d617d9cd122fc2e17b3bad2f2c3b5812c0f6f51898024a96c4839fa000e1
```
然后再在083这台机器上启动另外一个 redis 容器。
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_3 -d -e constraint:label_name==083 redis 7786300b8d2232c2335ac6161c715de23f9179d30eb5c7e9c4f920a4f1d39570
然后,分别启动两个容器,指定使用过滤器分别为红色和绿色
```sh
$ docker -H 192.168.0.2:12375 run -d -e constraint:color==red ubuntu:14.04 ping 127.0.0.1
252ffb48e64e9858c72241f5eedf6a3e4571b1ad926faf091db3e26672370f64
$ docker -H 192.168.0.2:12375 run -d -e constraint:color==green ubuntu:14.04 ping 127.0.0.1
3d6f8d7af8583416b17061d038545240c9e5c3be7067935d3ef2fbddce4b8136
```
现在来看下执行情况:
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7786300b8d22 redis:latest "/entrypoint.sh redi 15 minutes ago Up 53 seconds 6379/tcp 083/redis_3
4968d617d9cd redis:latest "/entrypoint.sh redi 16 minutes ago Up 2 minutes 6379/tcp 084/redis_2
fee1b7b9dde1 redis:latest "/entrypoint.sh redi 19 minutes ago Up 5 minutes 6379/tcp 084/redis_1
*注:指定标签中间是两个等号*
查看它们将被分配到指定节点上。
```sh
$ docker -H 192.168.0.2:12375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
252ffb48e64e ubuntu:14.04 "ping 127.0.0.1" 1 minutes ago Up 1 minutes Host-2/sick_galileo
3d6f8d7af858 ubuntu:14.04 "ping 127.0.0.1" 2 minutes ago Up 2 minutes Host-3/compassionate_ritchie
```
可以看到,执行结果跟预期的一样
另外Docker 内置了一些常见的过滤器,包括 `node``storagedriver``executiondriver``kernelversion``operatingsystem` 等。这些值可以通过 `docker info` 命令查看
但是如果指定一个不存在的标签的话来运行容器会报错。
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name redis_0 -d -e constraint:label_name==0 redis
FATA[0000] Error response from daemon: unable to find a node that satisfies label_name==0
例如,目前集群中各个节点的信息为:
```sh
$ docker -H 192.168.0.2:12375 info
Containers: 5
Images: 39
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 2
Host-2: 192.168.0.2:2375
└ Containers: 4
└ Reserved CPUs: 0 / 4
└ Reserved Memory: 1 GiB / 4.053 GiB
└ Labels: color=red, executiondriver=native-0.2, kernelversion=3.16.0-43-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs
Host-3: 192.168.0.3:2375
└ Containers: 1
└ Reserved CPUs: 0 / 8
└ Reserved Memory: 0 B / 16.46 GiB
└ Labels: color=green, executiondriver=native-0.2, kernelversion=3.16.0-30-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs
CPUs: 12
Total Memory: 20.51 GiB
Name: 946d65606f7c
```
###Affinity Filter
通过使用 Affinity Filter可以让一个容器紧挨着另一个容器启动也就是说让两个容器在同一个节点上面启动
### Affinity 过滤器
Affinity 过滤器允许用户在启动一个容器的时候,让它分配到某个已有容器的节点上
例如,下面我们将启动一个 nginx 容器,让它分配到已经运行某个 ubuntu 容器的节点上。
在 Constraint 过滤器的示例中,我们分别启动了两个 ubuntu 容器 `sick_galileo``compassionate_ritchie`,分别在 Host-2 和 Host-3 上。
现在其中一台机器上面启动一个 redis 容器
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis redis
ea13eddf667992c5d8296557d3c282dd8484bd262c81e2b5af061cdd6c82158d
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ea13eddf6679 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 6379/tcp 083/redis
现在启动一个 nginx 容器,让它跟容器 `sick_galileo` 放在一起,都放到 Host-2 节点上。可以通过 `-e affinity:container==<name or id>` 参数来实现
```sh
$ docker -H 192.168.0.2:12375 run -d -e affinity:container==sick_galileo nginx
```
然后再次启动个 redis 容器。
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis_1 -e affinity:container==redis redis
bac50c2e955211047a745008fd1086eaa16d7ae4f33c192f50412e8dcd0a14cd
rio@085:~$ sudo docker -H 192.168.1.83:2376 run -d --name redis_1 -e affinity:container==redis redis
bac50c2e955211047a745008fd1086eaa16d7ae4f33c192f50412e8dcd0a14cd
```
现在来查看下运行结果,可以看到三个容器都是在一台机器上运行
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
449ed25ad239 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 6379/tcp 083/redis_2
bac50c2e9552 redis:latest /entrypoint.sh redis 25 minutes ago Up 10 seconds 6379/tcp 083/redis_1
ea13eddf6679 redis:latest /entrypoint.sh redis 28 minutes ago Up 3 minutes 6379/tcp 083/redis
```
通过 `-e affinity:image=image_name` 命令可以指定只有已经下载了`image_name`镜像的机器才运行容器
```bash
sudo docker H 192.168.1.83:2376 run name redis1 d e affinity:image==redis redis
```
redis1 这个容器只会在已经下载了 redis 镜像的节点上运行。
然后启动个 redis 容器,让它跟容器 `compassionate_ritchie` 放在一起,都放到 Host-3 节点上
```bash
sudo docker -H 192.168.1.83:2376 run -d --name redis -e affinity:image==~redis redis
```
这条命令达到的效果是:在有 redis 镜像的节点上面启动一个名字叫做 redis 的容器,如果每个节点上面都没有 redis 容器,就按照默认的策略启动 redis 容器。
###Port Filter
Port 也会被认为是一个唯一的资源
```bash
sudo docker -H 192.168.1.83:2376 run -d -p 80:80 nginx
```sh
$ docker -H 192.168.0.2:12375 run -d -e affinity:container==compassionate_ritchie redis
```
执行完这条命令,之后任何使用 80 端口的容器都是启动失败。
查看所有容器运行情况。
```sh
$ docker -H 192.168.0.2:12375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a32f15aa8ee redis "/entrypoint.sh redis" 2 seconds ago Up 1 seconds 6379/tcp Host-3/awesome_darwin
d2b9a53e67d5 nginx "nginx -g 'daemon off" 29 seconds ago Up 28 seconds 80/tcp, 443/tcp Host-2/fervent_wilson
252ffb48e64e ubuntu:14.04 "ping 127.0.0.1" 2 minutes ago Up 2 minutes Host-2/sick_galileo
3d6f8d7af858 ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/compassionate_ritchie
```
### 其它过滤器
其它过滤器的使用方法也是大同小异,例如通过 `-e affinity:image==<name or id>` 来选择拥有指定镜像的节点;通过 `-e affinity:label_name==value` 来选择拥有指定标签的容器所允许的节点。
此外当容器端口需要映射到宿主机指定端口号的时候Swarm 也会自动分配容器到指定宿主机端口可用的节点。
当不同容器之间存在数据卷或链接依赖的时候Swarm 会分配这些容器到同一个节点上。

View File

@@ -1,9 +1,81 @@
## 安装
安装swarm的最简单的方式是使用Docker官方的swarm镜像
> $ sudo docker pull swarm
## 安装 Swarm
Swarm 安装有几种方式,可以基于 Docker Machine 来进行安装,也可以手动配置。为了能更容易理解 Swarm 的组件和更灵活的进行管理,推荐使用手动配置方式。
可以使用下面的命令来查看swarm是否成功安装
> $ sudo docker run --rm swarm -v
输出下面的形式则表示成功安装(具体输出根据swarm的版本变化)
> swarm version 0.2.0 (48fd993)
对于 Docker 1.12+ 版本Swarm 相关命令已经原生嵌入到了 Docker engine 的支持,对于较低版本的 Docker需要额外进行配置
### 下载镜像
Docker 官方已经提供了 Swarm 镜像使用,需要在所有被 Swarm 管理的 Docker 主机上下载该镜像。
```sh
$ docker pull swarm
```
可以使用下面的命令来查看 Swarm 版本,验证是否成功下载 Swarm 镜像。
```sh
$ docker run --rm swarm -v
swarm version 1.2.2 (34e3da3)
```
### 配置节点
Docker 主机在加入 Swarm 集群前,需要进行一些简单配置,添加 Docker daemon 的网络监听。
例如,在启动 Docker daemon 的时候通过 `-H` 参数:
```sh
$ sudo docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
```
*Docker 1.8.0 版本之前不支持 daemon 命令,可以用 -d 代替。*
如果是通过服务方式启动,则需要修改服务的配置文件。
以 Ubuntu 14.04 为例,配置文件为 `/etc/default/docker`(其他版本的 Linux 上略有不同)。
在文件的最后添加:
```sh
DOCKER_OPTS="$DOCKER_OPTS -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock"
```
### 启动集群
Docker 集群管理需要使用服务发现Service Discover功能Swarm 支持以下的几种方式DockerHub、本地文件、etcd、consel、zookeeper 和手动指定节点 IP 地址信息等。
除了手动指定外,这些方法原理上都是通过维护一套数据库机制,来管理集群中注册节点的 Docker daemon 的访问信息。
本地配置集群推荐使用 consel 作为服务发现后端。利用社区提供的 Docker 镜像,整个过程只需要三步即可完成。
#### 启动 Consel 服务后端
启动 consel 服务容器,映射到主机的 8500 端口。
```sh
$ docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap
```
获取到本地主机的地址作为 consul 的服务地址:`<consul_ip>:8500`
#### 启动管理节点
首先,启动一个主管理节点,映射到主机的 4000 端口,并获取所在主机地址为 `<manager0_ip>`。其中 4000 端口是 Swarm 管理器的默认监听端口,用户也可以指定映射为其它端口。
```sh
$ docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise <manager0_ip>:4000 consul://<consul_ip>:8500
```
为了提高高可用性,用户也可以启动从管理节点。假定获取所在主机地址为 `<manager1_ip>`
```sh
$ docker run -d swarm manage -H :4000 --replication --advertise <manager1_ip>:4000 consul://<consul_ip>:8500
```
#### 启动工作节点
需要在每个工作节点上启动 agent 服务。
获取节点的主机地址为 `<node_ip>`,并指定前面获取到的 consel 服务地址。
```sh
$ docker run -d swarm join --advertise=<node_ip>:2375 consul://<consul_ip>:8500
```
节点启动后,用户可以指定 Docker 服务地址为 `<manager0_ip>:4000>` 来测试各种 Docker 命令,可以看到整个 Swarm 集群就像一个虚拟的 Docker 主机一样正常工作。
由于 Swarm 实际上是通过 agent 调用了本地的 Docker daemon 来运行容器,当 Swarm 集群服务出现故障时,无法接受新的请求,但已经运行起来的容器将不会受到影响。

View File

@@ -1,16 +1,16 @@
## 简介
Docker Swarm 是 Docker公司官方在 2014 年 12月初发布的一套管理 Docker 集群的工具。它将一群 Docker 宿主机变成一个单一的,虚拟的主机。
## Swarm 简介
![Docker Swarm](_images/docker_swarm.png)
Swarm 使用标准的 Docker API 接口作为其前端访问入口,换言之,各种形式的 Docker 工具比如 DokkuComposeKraneDeisdocker-pyDocker 本身等都可以很容易的与 Swarm 进行集成
Docker Swarm Docker 公司推出的官方容器集群平台,基于 Go 语言实现,代码开源在 [https://github.com/docker/swarm](https://github.com/docker/swarm)。目前,包括 Rackspace 等平台都采用了 Swarm用户也很容易在 AWS 等公有云平台使用 Swarm。
![Swarm 结构图](../_images/swarm.png)
Swarm 的前身是 Beam 项目和 libswarm 项目首个正式版本Swarm V1在 2014 年 12 月初发布。为了提高可扩展性2016 年 2 月对架构进行重新设计,推出了 V2 版本,支持超过 1K 个节点。最新的 Docker Engine 已经集成了 SwarmKit加强了对 Swarm 的协作支持。
在使用 Swarm 管理docker 集群时,会有一个 swarm manager 以及若干的 swarm nodeswarm manager上运行 swarm daemon用户只需要跟 swarm manager 通信,然后 swarm manager 再根据discovery service的信息选择一个swarm node 来运行container
作为容器集群管理器Swarm 最大的优势之一就是 100% 支持标准的 Docker API。各种基于标准 API 的工具比如 Compose、docker-py、各种管理软件甚至 Docker 本身等都可以很容易的与 Swarm 进行集成。这大大方便了用户将原先基于单节点的系统移植到 Swarm 上。同时 Swarm 内置了对 Docker 网络插件的支持,用户可以很容易地部署跨主机的容器集群服务
值得注意的是 swarm daemon 只是一个任务调度器(scheduler)和路由器(router),它本身不运行容器,它只接受 Docker client 发送过来的请求,调度合适的 swarm node 来运行 container。这意味着即使 swarm daemon 由于某些原因挂掉了,已经运行起来的容器也不会有任何影响。
![Swarm 基本结构图](_images/swarm.png)
上图是来自官方的 V1 结构图。可以看出Swarm 是典型的 master-slave 结构,通过发现服务来选举 manager。manager 是中心管理节点,各个 node 上运行 agent 接受 manager 的统一管理。
有以下两点需要注意:
在 V2 中,集群中会自动通过 Raft 协议分布式选举出 manager 节点无需额外的发现服务支持避免了单点瓶颈。同时V2 中内置了基于 DNS 的负载均衡和对外部负载均衡机制的集成支持。
* 集群中的每台节点上面的 Docker 的版本都不能小于1.4
* 为了让 swarm manager 能够跟每台 swarm node 进行通信,集群中的每台节点的 Docker daemon 都必须监听同一个网络接口。
目前Swarm V1 支持 Docker 版本为 1.6.0+V2 支持 Docker 版本为 1.12.0+。本章将以 Swarm V1 为主进行介绍,并结合 V2 的部分最新特性。

View File

@@ -1,73 +1,73 @@
## swarm 调度策略
swarm支持多种调度策略来选择节点。每次在swarm启动container的时候swarm会根据选择的调度策略来选择节点运行container。目前支持的有:spread,binpackrandom。
## Swarm 中的调度器
调度是集群十分重要的功能Swarm 目前支持三种调度策略:`spread``binpack``random`
在执行`swarm manage`命令启动 swarm 集群的时候可以通过 `--strategy` 参数指定默认的是spread。
在执行`swarm manage`命令启动管理服务的时候可以通过 `--strategy` 参数指定调度策略,默认的是 `spread`
spread和binpack策略会根据每台节点的可用CPU内存以及正在运行的containers的数量来给各个节点分级而random策略顾名思义他不会做任何的计算只是单纯的随机选择一个节点来启动container。这种策略一般只做调试用。
简单来说,这三种调度策略的优化目标如下:
使用spread策略swarm会选择一个正在运行的container的数量最少的那个节点来运行container。这种情况会导致启动的container会尽可能的分布在不同的机器上运行这样的好处就是如果有节点坏掉的时候不会损失太多的container。
* `spread`:如果节点配置相同,选择一个正在运行的容器数量最少的那个节点,即尽量平摊容器到各个节点;
* `binpack`:跟 `spread` 相反,尽可能的把所有的容器放在一台节点上面运行,即尽量少用节点,避免容器碎片化。
* `random`:直接随机分配,不考虑集群中节点的状态,方便进行测试使用。
binpack 则相反这种情况下swarm会尽可能的把所有的容器放在一台节点上面运行。这种策略会避免容器碎片化因为他会把未使用的机器分配给更大的容器带来的好处就是swarm会使用最少的节点运行最多的容器。
### spread 调度策略
仍然以之前创建好的集群为例,来演示下 spread 策略的行为。
### spread 策略
先来演示下 spread 策略的情况。
```bash
rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=spread file:///tmp/cluster
7609ac2e463f435c271d17887b7d1db223a5d696bf3f47f86925c781c000cb60
ats@sclu083:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7609ac2e463f swarm:latest "/swarm manage --str 6 seconds ago Up 5 seconds 0.0.0.0:2376->2375/tcp focused_babbage
```
三台机器除了83运行了 Swarm之外其他的都没有运行任何一个容器现在在85这台节点上面在swarm集群上启动一个容器
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-1 -d -P redis
2553799f1372b432e9b3311b73e327915d996b6b095a30de3c91a47ff06ce981
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2553799f1372 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.84:32770->6379/tcp 084/node-1
```
启动一个 redis 容器,查看结果
```bash
`192.168.0.2` 节点启动管理服务,管理 token://946d65606f7c2f49766e4dddac5b4365 的集群。
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-2 -d -P redis
7965a17fb943dc6404e2c14fb8585967e114addca068f233fcaf60c13bcf2190
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7965a17fb943 redis:latest /entrypoint.sh redis Less than a second ago Up 1 seconds 192.168.1.124:49154->6379/tcp 124/node-2
2553799f1372 redis:latest /entrypoint.sh redis 29 minutes ago Up 4 minutes 192.168.1.84:32770->6379/tcp 084/node-1
```
再次启动一个 redis 容器,查看结果
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-3 -d -P redis
65e1ed758b53fbf441433a6cb47d288c51235257cf1bf92e04a63a8079e76bee
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7965a17fb943 redis:latest /entrypoint.sh redis Less than a second ago Up 4 minutes 192.168.1.227:49154->6379/tcp 124/node-2
65e1ed758b53 redis:latest /entrypoint.sh redis 25 minutes ago Up 17 seconds 192.168.1.83:32770->6379/tcp 083/node-3
2553799f1372 redis:latest /entrypoint.sh redis 33 minutes ago Up 8 minutes 192.168.1.84:32770->6379/tcp 084/node-1
```
可以看到三个容器都是分布在不同的节点上面的。
### binpack 策略
现在来看看binpack策略下的情况。在083上面执行命令
```bash
rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage --strategy=binpack file:///tmp/cluster
f1c9affd5a0567870a45a8eae57fec7c78f3825f3a53fd324157011aa0111ac5
```sh
$ docker run -d -p 12375:2375 swarm manage --strategy "spread" token://946d65606f7c2f49766e4dddac5b4365
c6f25e6e6abbe45c8bcf75ac674f2b64d5f31a5c6070d64ba954a0309b197930
```
现在在集群中启动三个 redis 容器,查看分布情况:
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-1 -d -P redis
18ceefa5e86f06025cf7c15919fa64a417a9d865c27d97a0ab4c7315118e348c
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-2 -d -P redis
7e778bde1a99c5cbe4701e06935157a6572fb8093fe21517845f5296c1a91bb2
rio@085:~$ sudo docker -H 192.168.1.83:2376 run --name node-3 -d -P redis
2195086965a783f0c2b2f8af65083c770f8bd454d98b7a94d0f670e73eea05f8
rio@085:~$ sudo docker -H 192.168.1.83:2376 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2195086965a7 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.83:32773->6379/tcp 083/node-3
7e778bde1a99 redis:latest /entrypoint.sh redis 24 minutes ago Up Less than a second 192.168.1.83:32772->6379/tcp 083/node-2
18ceefa5e86f redis:latest /entrypoint.sh redis 25 minutes ago Up 22 seconds 192.168.1.83:32771->6379/tcp 083/node-1
列出集群中节点。
```sh
$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365
192.168.0.3:2375
192.168.0.2:2375
```
可以看到,所有的容器都是分布在同一个节点上运行的。
此时,两个节点上除了 swarm 外都没有运行其它容器。
启动一个 ubuntu 容器。
```sh
$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1
bac3dfda5306181140fc959969d738549d607bc598390f57bdd432d86f16f069
```
查看发现它实际上被调度到了 `192.168.0.3` 节点(当节点配置相同时候,初始节点随机选择)。
再次启动一个 ubuntu 容器。
```sh
$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1
8247067ba3a31e0cb692a8373405f95920a10389ce3c2a07091408281695281c
```
查看它的位置,发现被调度到了另外一个节点:`192.168.0.2` 节点。
```sh
$ docker -H 192.168.0.2:12375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8247067ba3a3 ubuntu:14.04 "ping 127.0.0.1" 1 minutes ago Up 1 minutes Host-2/sick_galileo
bac3dfda5306 ubuntu:14.04 "ping 127.0.0.1" 2 minutes ago Up 2 minutes Host-3/compassionate_ritchie
```
当节点配置不同的时候,`spread`会更愿意分配到配置较高的节点上。
### binpack 调度策略
现在来看看 `binpack` 策略下的情况。
直接启动若干 ubuntu 容器,并查看它们的位置。
```sh
$ docker -H 192.168.0.2:12375 run -d ubuntu:14.04 ping 127.0.0.1
$ docker -H 192.168.0.2:12375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c4f45eba866 ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/hopeful_brown
5e650541233c ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/pensive_wright
99c5a092530a ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/naughty_engelbart
4ab392c26eb2 ubuntu:14.04 "ping 127.0.0.1" 3 minutes ago Up 3 minutes Host-3/thirsty_mclean
```
可以看到,所有的容器都是分布在同一个节点(`192.168.0.3`)上运行的。

97
swarm/servicebackend.md Normal file
View File

@@ -0,0 +1,97 @@
## 使用其它服务发现后端
Swarm 目前可以支持多种服务发现后端,这些后端功能上都是一致的,即维护属于某个集群的节点的信息。不同方案并无优劣之分,在实际使用时候,可以结合自身需求和环境限制进行选择,甚至自己定制其它方案。
使用中可以通过不同的路径来选择特定的服务发现后端机制。
* `token://<token>`:使用 DockerHub 提供的服务,适用于可以访问公网情况;
* `file://path/to/file`:使用本地文件,需要手动管理;
* `consul://<ip>/<path>`:使用 consul 服务,私有环境推荐;
* `etcd://<ip1>,<ip2>/<path>`:使用 etcd 服务,私有环境推荐;
* `zk://<ip1>,<ip2>/<path>`:使用 zookeeper 服务,私有环境推荐;
* `[nodes://]<ip1>,<ip2>`:手动指定集群中节点的地址,方便进行服务测试。
### 使用文件
使用本地文件的方式十分简单,就是讲所有属于某个集群的节点的 Docker daemon 信息写入一个文件中,然后让 manager 从这个文件中直接读取相关信息。
首先,在 Swarm 管理节点(`192.168.0.2`)上新建一个文件,把要加入集群的机器的 Docker daemon 信息写入文件:
```sh
$ tee /tmp/cluster_info <<-'EOF'
192.168.0.2:2375
192.168.0.3:2375
EOF
```
然后,本地执行 `swarm manage` 命令,并指定服务发现机制为本地文件,注意因为是容器方式运行 manager需要将本地文件挂载到容器内。
```sh
$ docker run -d -p 12375:2375 -v /tmp/cluster_info:/tmp/cluster_info swarm manage file:///tmp/cluster_info
```
接下来就可以通过使用 Swarm 服务来进行管理了,例如使用 info 查看所有节点的信息。
```sh
$ docker -H 192.168.0.2:12375 info
Containers: 18
Images: 36
Role: primary
Strategy: spread
Filters: health, port, dependency, affinity, constraint
Nodes: 2
Host-1: 192.168.0.2:2375
└ Containers: 15
└ Reserved CPUs: 0 / 4
└ Reserved Memory: 1 GiB / 4.053 GiB
└ Labels: executiondriver=native-0.2, kernelversion=3.16.0-43-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs
Host-2: 192.168.0.3:2375
└ Containers: 3
└ Reserved CPUs: 0 / 8
└ Reserved Memory: 0 B / 16.46 GiB
└ Labels: executiondriver=native-0.2, kernelversion=3.16.0-30-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs
CPUs: 12
Total Memory: 20.51 GiB
Name: e71eb5f1d48b
```
### 其它发现服务后端
其它服务发现后端的使用方法,也是大同小异,不同之处在于使用 Swarm 命令时指定的路径格式不同。
例如,对于前面介绍的 consul 服务后端来说。
快速部署一个 consul 服务的命令为:
```sh
$ docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap
```
之后创建 Swarm 的管理服务,指定使用 consul 服务,管理端口监听在本地的 4000 端口。
```sh
$ docker run -d -p 4000:4000 swarm manage -H :4000 --replication --advertise <manager_ip>:4000 consul://<consul_ip>:8500
```
Swarm 节点注册时候命令格式类似于:
```sh
$ swarm join --advertise=<node_ip:2375> consul://<consul_addr>/<optional path prefix>
```
对于 etcd 服务后端来说,节点注册时候命令格式类似于:
```sh
$ swarm join --addr=<node_addr:2375> etcd://<etcd_addr1>,<etcd_addr2>/<optional path prefix>
```
启动管理服务时候,格式类似于:
```sh
$ swarm manage -H tcp://<manager_ip>:4000 etcd://<etcd_addr1>,<etcd_addr2>/<optional path prefix>
```
### 地址和端口的范围匹配
对于基于文件,以及手动指定节点信息两种服务发现后端机制来说,其中地址和端口域可以支持指定一个范围,以一次性指定多个地址。
例如:
* `192.168.0.[2:10]:2375` 代表 `192.168.0.2:2375` -- `192.168.0.10:2375` 一共 9 个地址;
* `192.168.0.2:[2:9]375` 代表 `192.168.0.2:2375` -- `192.168.0.2:9375` 一共 8 个地址。

10
swarm/summary.md Normal file
View File

@@ -0,0 +1,10 @@
## 本章小结
本章笔者介绍了 Docker Swarm 的安装、使用和主要功能。
通过使用 Swarm用户可以将若干 Docker 主机节点组成的集群当作一个大的虚拟 Docker 主机使用。并且,原先基于单机的 Docker 应用,可以无缝的迁移到 Swarm 上来。
实现这些功能的前提是服务自动发现能力。在现代分布式系统中,服务的自动发现、注册、更新等能力将成为系统的基本保障和重要基础。
在生产环境中Swarm 的管理节点和发现服务后端要采用高可用性上的保护,可以采用集群模式。
值得一提的是Swarm V2 功能已经被无缝嵌入到了 Docker 1.12+ 版本中,用户今后可以直接使用 Docker 命令来完成相关功能的配置,这将使得集群功能的管理更加简便。

View File

@@ -1,170 +1,181 @@
## 使用
在使用 swarm 管理集群前,需要把集群中所有的节点的 docker daemon 的监听方式更改为 `0.0.0.0:2375`
## 使用 Swarm
前面演示了基于 consel 服务发现后端来配置一个本地 Swarm 集群。其中consel 也可以被替换为 etcd、zookeeper 等
可以有两种方式达到这个目的第一种是在启动docker daemon的时候指定
```bash
sudo docker -H 0.0.0.0:2375&
另外一个更方便的方式是直接使用 DockerHub 提供的免费服务发现后端。
下面使用这种方式来演示 Swarm 的主要操作,包括:
* create创建一个集群
* list列出集群中的节点
* manage管理一个集群
* join让节点加入到某个集群。
注意,使用 DockerHub 的服务发现后端,需要各个节点能通过公网访问到 DockerHub 的服务接口。
### 创建集群 id
在任意一台安装了 Swarm 的机器上执行 `swarm create` 命令来在 DockerHub 服务上进行注册。
Swarm 会通过服务发现后端(此处为 DockerHub 提供)来获取一个唯一的由数字和字母组成的 token用来标识要管理的集群。
```sh
$ docker run --rm swarm create
946d65606f7c2f49766e4dddac5b4365
```
第二种方式是直接修改 Docker 的配置文件(Ubuntu 上是 `/etc/default/docker`,其他版本的 Linux 上略有不同)
注意返回的字符串,这是集群的唯一 id加入集群的各个节点将需要这个信息。
在文件的最后添加下面这句代码:
```bash
DOCKER_OPTS="-H 0.0.0.0:2375 -H unix:///var/run/docker.sock"
### 配置集群节点
在所有要加入集群的普通节点上面执行 `swarm join` 命令,表示把这台机器加入指定集群当中。
例如某台机器 IP 地址为 `192.168.0.2`,将其加入我们刚创建的 `946d65606f7c2f49766e4dddac5b4365` 集群,则可以通过:
```sh
$ docker run --rm swarm join --addr=192.168.0.2:2375 token://946d65606f7c2f49766e4dddac5b4365
time="2015-12-09T08:59:43Z" level=info msg="Registering on the discovery service every 20s..." addr="192.168.0.2:2375" discovery="token://946d65606f7c2f49766e4dddac5b4365"
...
```
*注:其中 `--addr` 指定的 IP 地址信息将被发送给服务发现后端用以区分集群不同的节点。manager 服务必须要通过这个地址可以访问到该节点。*
需要注意的是,一定要在所有希望被 Swarm 管理的节点上进行的。修改之后要重启 Docker
```bash
sudo service docker restart
通过控制台可以看到,上述命令执行后,默认每隔 20 秒(可以通过 `--heartbeat` 选项指定),会输出一条心跳信息。对于发现服务后端来说,默认如果超过 60 秒(可以通过 `--ttl` 选项指定)没有收到心跳信息,则将节点从列表中删除。
如果不希望看到输出日志信息,则可以用 `-d` 选项替换 `--rm` 选项,让服务后台执行。
执行 `swarm join` 命令实际上是通过 agent 把自己的信息注册到发现服务上,因此,此时对于后端的发现服务来说,已经可以看到有若干节点注册上来了。那么,如何管理和使用这些节点呢,这就得需要 Swarm 的 manager 服务了。
### 配置管理节点
配置管理节点需要通过 `swarm manage` 命令,该命令将启动 manager 服务,默认监听到 `2375` 端口,所有对集群的管理可以通过该服务接口进行。
读者可能注意到manager 服务默认监听的端口跟 Docker 服务监听端口是一样的,这是为了兼容其它基于 Docker 的服务,可以无缝地切换到 Swarm 平台上来。
仍然在节点 `192.168.0.2` 进行操作。由于我们是采用 Docker 容器形式启动 manager 服务,本地的 `2375` 端口已经被 Docker Daemon 占用。我们将 manager 服务监听端口映射到本地一个空闲的 `12375` 端口。
```sh
$ docker run -d -p 12375:2375 swarm manage token://946d65606f7c2f49766e4dddac5b4365
1e1ca8c4117b6b7271efc693f9685b4e907d8dc95324350392b21e94b3cffd18
```
Docker 集群管理需要使用服务发现(Discovery service backend)功能Swarm支持以下的几种方式DockerHub 提供的服务发现功能本地的文件etcdconsulzookeeper 和 IP 列表,本文会详细讲解前两种方式,其他的用法都是大同小异的
可以通过 `docker ps` 命令来查看启动的 swarm manager 服务容器
先说一下本次试验的环境本次试验包括三台机器IP地址分别为192.168.1.84,192.168.1.83和192.168.1.124.利用这三台机器组成一个docker集群其中83这台机器同时充当swarm manager节点。
### 使用 DockerHub 提供的服务发现功能
#### 创建集群 token
在上面三台机器中的任何一台机器上面执行 `swarm create` 命令来获取一个集群标志。这条命令执行完毕后Swarm 会前往 DockerHub 上内置的发现服务中获取一个全球唯一的 token用来标识要管理的集群。
```bash
sudo docker run --rm swarm create
```sh
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1e1ca8c4117b swarm "/swarm manage token:" 11 seconds ago Up 10 seconds 0.0.0.0:12375->2375/tcp jovial_rosalind
```
我们在84这台机器上执行这条命令输出如下
```bash
rio@084:~$ sudo docker run --rm swarm create
b7625e5a7a2dc7f8c4faacf2b510078e
命令如果执行成功会返回刚启动的 Swarm 容器的 ID此时一个简单的 Swarm 集群就已经搭建起来了,包括一个普通节点和一个管理节点。
### 查看集群节点列表
集群启动成功以后,用户可以在任何一台节点上使用 `swarm list` 命令查看集群中的节点列表。例如
```sh
$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365
192.168.0.2:2375
```
显示正是之前用 `swarm join` 命令加入集群的节点的地址。
我们在另外一台节点 `192.168.0.3` 上同样使用 `swarm join` 命令新加入一个节点:
```sh
$docker run --rm swarm join --addr=192.168.0.3:2375 token://946d65606f7c2f49766e4dddac5b4365
time="2015-12-10T02:05:34Z" level=info msg="Registering on the discovery service every 20s..." addr="192.168.0.3:2375" discovery="token://946d65606f7c2f49766e4dddac5b4365"
...
```
可以看到我们返回的 token 是 `b7625e5a7a2dc7f8c4faacf2b510078e`,每次返回的结果都是不一样的。这个 token 一定要记住,后面的操作都会用到这个 token。
再次使用 `swarm list` 命令查看集群中的节点列表信息,可以看到新加入的节点:
#### 加入集群
在所有要加入集群的节点上面执行 `swarm join` 命令,表示要把这台机器加入这个集群当中。在本次试验中,就是要在 83、84 和 124 这三台机器上执行下面的这条命令:
```bash
sudo docker run -d swarm join --addr=ip_address:2375 token://token_id
```sh
$ docker run --rm swarm list token://946d65606f7c2f49766e4dddac5b4365
192.168.0.3:2375
192.168.0.2:2375
```
其中的 ip_address 换成执行这条命令的机器的 IPtoken_id 换成上一步执行 `swarm create` 返回的 token。
在83这台机器上面的执行结果如下
```bash
rio@083:~$ sudo docker run -d swarm join --addr=192.168.1.83:2375 token://b7625e5a7a2dc7f8c4faacf2b510078e
3b3d9da603d7c121588f796eab723458af5938606282787fcbb03b6f1ac2000b
### 使用集群服务
那么,怎么使用 Swarm 提供的服务呢?
实际上,所有 Docker 客户端可以继续使用,只要指定使用 Swarm manager 服务的监听地址即可。
例如manager 服务监听的地址为 `192.168.0.2:12375`,则可以通过指定 `-H 192.168.0.2:12375` 选项来继续使用 Docker 客户端,执行任意 Docker 命令,例如 `ps``info``run` 等等。
在任意节点上使用 `docker run` 来启动若干容器,例如
```sh
$docker -H 192.168.0.2:12375:12375 run -d ubuntu ping 127.0.0.1
4c9bccbf86fb6e2243da58c1b15e9378fac362783a663426bbe7058eea84de46
```
这条命令通过 `-d` 参数启动了一个容器使得83这台机器加入到集群。如果这个容器被停止或者被删除83这台机器就会从集群中消失。
#### 启动swarm manager
因为我们要使用 83 这台机器充当 swarm 管理节点所以需要在83这台机器上面执行 `swarm manage` 命令:
```bash
sudo docker run -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e
使用 `ps` 命令查看集群中正在运行的容器。
```sh
$ docker -H 192.168.0.2:12375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c9bccbf86fb ubuntu "ping 127.0.0.1" About a minute ago Up About a minute clever_wright
730061a3801a registry:latest "docker-registry" 2 minutes ago Up 2 minutes 192.168.0.2:5000->5000/tcp Host-1/registry_registry_1
72d99f24a06f redis:3.0 "/entrypoint.sh redis" 2 minutes ago Up 2 minutes 6379/tcp Host-1/registry_redis_1,Host-1/registry_registry_1/redis,Host-1/registry_registry_1/redis_1,Host-1/registry_registry_1/registry_redis_1
```
执行结果如下:
```bash
rio@083:~$ sudo docker run -d -p 2376:2375 swarm manage token://b7625e5a7a2dc7f8c4faacf2b510078e
83de3e9149b7a0ef49916d1dbe073e44e8c31c2fcbe98d962a4f85380ef25f76
```
这条命令如果执行成功会返回已经启动的 Swarm 的容器的 ID此时整个集群已经启动起来了。
现在通过 `docker ps` 命令来看下有没有启动成功
```bash
rio@083:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
83de3e9149b7 swarm:latest "/swarm manage token 4 minutes ago Up 4 minutes 0.0.0.0:2376->2375/tcp stupefied_stallman
```
可以看到Swarm 已经成功启动。
在执行 `Swarm manage` 这条命令的时候,有几点需要注意的:
输出结果中显示目前集群中正在运行的容器(注意不包括 Swarm manager 服务容器),可以在不同节点上使用 `docker ps` 查看本地容器,发现这些容器实际上可能运行在集群中多个节点上(被 Swarm 调度策略进行分配)
* 这条命令需要在充当 swarm 管理者的机器上执行
* Swarm 要以 daemon 的形式执行
* 映射的端口可以使任意的除了 2375 以外的并且是未被占用的端口,但一定不能是 2375 这个端口,因为 2375 已经被 Docker 本身给占用了。
使用 info 查看所有节点的信息。
集群启动成功以后,现在我们可以在任何一台节点上使用 `swarm list` 命令查看集群中的节点了,本实验在 124 这台机器上执行 `swarm list` 命令:
```bash
rio@124:~$ sudo docker run --rm swarm list token://b7625e5a7a2dc7f8c4faacf2b510078e
192.168.1.84:2375
192.168.1.124:2375
192.168.1.83:2375
```
输出结果列出的IP地址正是我们使用 `swarm join` 命令加入集群的机器的IP地址。
现在我们可以在任何一台安装了 Docker 的机器上面通过命令(命令中要指明swarm manager机器的IP地址)来在集群中运行container了。
本次试验,我们在 192.168.1.85 这台机器上使用 `docker info` 命令来查看集群中的节点的信息。
其中 info 也可以换成其他的 Docker 支持的命令。
```bash
rio@085:~$ sudo docker -H 192.168.1.83:2376 info
Containers: 8
```sh
$ docker -H 192.168.0.2:12375 info
Containers: 18
Images: 36
Role: primary
Strategy: spread
Filters: affinity, health, constraint, port, dependency
Filters: health, port, dependency, affinity, constraint
Nodes: 2
sclu083: 192.168.1.83:2375
└ Containers: 1
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 4.054 GiB
sclu084: 192.168.1.84:2375
└ Containers: 7
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 4.053 GiB
```
结果输出显示这个集群中只有两个节点IP地址分别是 192.168.1.83 和 192.168.1.84,结果不对呀,我们明明把三台机器加入了这个集群,还有 124 这一台机器呢?
经过排查,发现是忘了修改 124 这台机器上面改 docker daemon 的监听方式,只要按照上面的步骤修改写 docker daemon 的监听方式就可以了。
在使用这个方法的时候使用swarm create可能会因为网络的原因会出现类似于下面的这个问题
```bash
rio@227:~$ sudo docker run --rm swarm create
[sudo] password for rio:
time="2015-05-19T12:59:26Z" level=fatal msg="Post https://discovery-stage.hub.docker.com/v1/clusters: dial tcp: i/o timeout"
```
### 使用文件
第二种方法相对于第一种方法要简单得多,也不会出现类似于上面的问题。
第一步:在 swarm 管理节点上新建一个文件,把要加入集群的机器 IP 地址和端口号写入文件中本次试验就是要在83这台机器上面操作
```bash
rio@083:~$ echo 192.168.1.83:2375 >> cluster
rio@083:~$ echo 192.168.1.84:2375 >> cluster
rio@083:~$ echo 192.168.1.124:2375 >> cluster
rio@083:~$ cat cluster
192.168.1.83:2375
192.168.1.84:2375
192.168.1.124:2375
```
第二步在083这台机器上面执行 `swarm manage` 这条命令:
```bash
rio@083:~$ sudo docker run -d -p 2376:2375 -v $(pwd)/cluster:/tmp/cluster swarm manage file:///tmp/cluster
364af1f25b776f99927b8ae26ca8db5a6fe8ab8cc1e4629a5a68b48951f598ad
```
使用`docker ps`来查看有没有启动成功:
```bash
rio@083:~$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
364af1f25b77 swarm:latest "/swarm manage file: About a minute ago Up About a minute 0.0.0.0:2376->2375/tcp happy_euclid
```
可以看到,此时整个集群已经启动成功。
在使用这条命令的时候需要注意的是注意:这里一定要使用-v命令因为cluster文件是在本机上面启动的容器默认是访问不到的所以要通过-v命令共享。
接下来的就可以在任何一台安装了docker的机器上面通过命令使用集群同样的在85这台机器上执行docker info命令查看集群的节点信息
```bash
rio@s085:~$ sudo docker -H 192.168.1.83:2376 info
Containers: 9
Strategy: spread
Filters: affinity, health, constraint, port, dependency
Nodes: 3
atsgxxx: 192.168.1.227:2375
└ Containers: 0
Host-1: 192.168.0.2:2375
└ Containers: 15
└ Reserved CPUs: 0 / 4
└ Reserved Memory: 0 B / 2.052 GiB
sclu083: 192.168.1.83:2375
└ Containers: 2
Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 4.054 GiB
sclu084: 192.168.1.84:2375
Containers: 7
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 4.053 GiB
└ Reserved Memory: 1 GiB / 4.053 GiB
└ Labels: executiondriver=native-0.2, kernelversion=3.16.0-43-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs
Host-2: 192.168.0.3:2375
Containers: 3
└ Reserved CPUs: 0 / 8
└ Reserved Memory: 0 B / 16.46 GiB
Labels: executiondriver=native-0.2, kernelversion=3.16.0-30-generic, operatingsystem=Ubuntu 14.04.3 LTS, storagedriver=aufs
CPUs: 12
Total Memory: 20.51 GiB
Name: 1e1ca8c4117b
```
结果输出显示这个集群目前只有两个节点,地址分别是 `192.168.0.2``192.168.0.3`
类似的,也可以通过 Compose 模板来启动多个服务。不过请注意,要想让服务分布到多个 Swarm 节点上,需要采用版本 2 的写法。
### 使用网络
Swarm 为了支持跨主机的网络,默认采用了 `overlay` 网络类型,实现上通过 vxlan 来构建联通整个 Swarm 集群的网络。
首先,在集群中所有节点上,添加配置 Docker daemon 选项:
```
--cluster-store=<DISCOVERY_HOST:PORT> --cluster-advertise=<DOCKER_DAEMON_HOST:PORT>
```
以 consul 服务为例,可能类似:
```sh
--cluster-store=consul://<consul 服务地址>:8500 --cluster-advertise=192.168.0.3:2375
```
之后重启 Docker 服务。
首先,创建一个网络。
```sh
$ docker -H 192.168.0.2:12375 network create swarm_network
```
查看网络,将看到一个 overlay 类型的网络。
```sh
$ docker -H 192.168.0.2:12375 network ls
NETWORK ID NAME DRIVER
6edf2d16ec97 swarm_network overlay
```
此时,所有添加到这个网络上的容器将自动被分配到集群中的节点上,并且彼此联通。