第二章 创建Swarm集群

继续上一章 Docker 1.12 Swarm Mode集群实战(第一章) 的内容, 为了产生更多的docker币,我们需要搭建一个swarm集群来scale out我们的docker币应用,解决单节点的性能瓶颈。

2.1 Swarm Mode简介

Docker Engine 1.12及后续版本集成了SwarmKit编排服务,即Swarm Mode。它将服务对象引入到docker中,提供swarm集群管理的原生支持并实现scaling、rolling update、service discovery、load balance、routing mesh等特性。

基本概念

  • 节点(Node)为Swarm集群中的一个Docker Engine实例。其中管理节点(Manager Node)负责swarm集群管理并向工作节点分配任务;工作节点(Work Node)接受并执行来自管理节点的Task。简单可理解为一个Node就是一台Docker宿主机,管理节点为领导,工作节点为小兵。

需要注意的是领导也会干小兵的活儿,真是个好领导啊…而且小兵也可以根据需求随时提拔成领导,真是个好团队啊…

  • 服务(Service)是对在worker nodes所运行一组任务的定义,它是整个swarm的核心,一个Service由多个任务组成。
  • 任务(Task)包含Docker容器和容器中运行的命令或应用,它是swarm中被调度的最小单元。简单可理解为一个Task就是一个容器。

Swarm Mode下主要使用三组新的命令行工具创建和管理一个Swarm集群:

  • docker swarm:开启swarm模式; 加入Swarm集群; 配置集群参数
  • docker node: 查询集群节点信息; 提升/移除一个管理节点; 管理swarm节点主机
  • docker service: 创建管理service

2.2 创建Swarm集群

在node01上初始化swarm集群:

# docker swarm init --advertise-addr 192.168.33.101

Swarm initialized: current node (7e2vvnlakrrv2p0omxgl2lflz) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join \

--token SWMTKN-1-4d8z30svnj6wi8y64ttzirpildro5vego1qrrldepj8auwxa6l-4l4b6o7q1wnjyiwsubkpffkkn \

192.168.33.101:2377

To add a manager to this swarm, run the following command:

docker swarm join \

--token SWMTKN-1-4d8z30svnj6wi8y64ttzirpildro5vego1qrrldepj8auwxa6l-3e8p1ojarz8rdq1rx0ves1a9o \

192.168.33.101:2377

NOTE:

  • 你只需要在一个node上初始化swarm集群, 其他node加入这个集群就行了, 所以以上命令只需要在node01上运行。
  • –advertise-addr参数, 后面跟你swarm集群的通讯地址, 这里是node01的IP地址。
  • 命令输出的提示很人性化吧,在需要的管理/工作节点复制粘贴运行即可加入到swarm集群中

将node01以manager角色加入swarm集群

docker swarm join \

--token SWMTKN-1-4d8z30svnj6wi8y64ttzirpildro5vego1qrrldepj8auwxa6l-3e8p1ojarz8rdq1rx0ves1a9o \

192.168.33.101:2377

检查node01 docker swarm mode信息:

# docker info

...

Swarm: active

NodeID: 7e2vvnlakrrv2p0omxgl2lflz

Is Manager: true

ClusterID: 0hhbs9vhvnpovil91d6z87txo

Managers: 1

Nodes: 1

Orchestration:

Task History Retention Limit: 5

Raft:

Snapshot interval: 10000

Heartbeat tick: 1

Election tick: 3

Dispatcher:

Heartbeat period: 5 seconds

CA configuration:

Expiry duration: 3 months

Node Address: 192.168.33.101

...

查看swarm集群node列表

# docker node ls

ID                      HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS

7e2vvnlakrrv2p0omxgl2lflz *  node01    Ready   Active        Leader

可以看到,我们的Swarm集群中只有一个管理节点。

现在我们把其他节点也加入我们的集群中
在node01通过ssh, 在node02-node05上执行上面的加入集群命令:

# for N in $(seq 2 5); \

do ssh node0$N \

docker swarm join \

--token SWMTKN-1-4d8z30svnj6wi8y64ttzirpildro5vego1qrrldepj8auwxa6l-4l4b6o7q1wnjyiwsubkpffkkn \

192.168.33.101:2377 \

;done

友情提示,如果你不记得初始化后提示加入swarm集群的命令和密钥也没关系,可以使用如下方式查看worker节点和manager节点的加入命令

# docker swarm join-token worker

# docker swarm join-token manager

再次检查集群节点列表, 我们可以看到所有的服务器都已经加入swarm集群了。

# docker node ls

ID            HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS

0frlcbt1xp0kggs64k5ktqrwj    node02    Ready   Active

6o60ktooinsrej8dcwncq8ibc    node04    Ready   Active

7e2vvnlakrrv2p0omxgl2lflz *  node01    Ready   Active        Leader

bsak0gszy07gh88tmo7lh5033    node05    Ready   Active

cmn6f714no0hn7c4xi9l0xs6h    node03    Ready   Active

不过现在我们的集群只有一个manager节点,即node01。为了swarm集群的高可用,避免单点故障. 我们希望建立多个manager节点集群.
只需要通过如下命令, 提升node02和node03节点为manager节点:

# docker node promote node02 node03

Node node02 promoted to a manager in the swarm.

Node node03 promoted to a manager in the swarm.

# 查看swarm集群node列表

# docker node ls

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS

0frlcbt1xp0kggs64k5ktqrwj    node02    Ready   Active        Reachable

6o60ktooinsrej8dcwncq8ibc    node04    Ready   Active

7e2vvnlakrrv2p0omxgl2lflz *  node01    Ready   Active        Leader

bsak0gszy07gh88tmo7lh5033    node05    Ready   Active

cmn6f714no0hn7c4xi9l0xs6h    node03    Ready   Active        Reachable

我们可以看到, 已经有3个manager节点了, 一个Leader节点, 两个Reachable节点.

现在你也可以在node02和node03上面管理整个swarm集群.

# ssh node02 docker node ls

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS

0frlcbt1xp0kggs64k5ktqrwj *  node02    Ready   Active        Reachable

6o60ktooinsrej8dcwncq8ibc    node04    Ready   Active

7e2vvnlakrrv2p0omxgl2lflz    node01    Ready   Active        Leader

bsak0gszy07gh88tmo7lh5033    node05    Ready   Active

cmn6f714no0hn7c4xi9l0xs6h    node03    Ready   Active        Reachable

# ssh node03 docker node ls

ID                           HOSTNAME  STATUS  AVAILABILITY  MANAGER STATUS

0frlcbt1xp0kggs64k5ktqrwj    node02    Ready   Active        Reachable

6o60ktooinsrej8dcwncq8ibc    node04    Ready   Active

7e2vvnlakrrv2p0omxgl2lflz    node01    Ready   Active        Leader

bsak0gszy07gh88tmo7lh5033    node05    Ready   Active

cmn6f714no0hn7c4xi9l0xs6h *  node03    Ready   Active        Reachable

好了,到此我们的swarm集群就搭建完毕了。超级简单吧~~

2.3 在Swarm集群运行Service

有了Docker Swarm集群,我们如何把我们的应用跑在Swarm集群上呢?

很简单, 将我们原来我们使用的docker run命令替换成docker service create就行了,命令后面的格式和选项全都一样。

使用docker service命令去创建容器服务.

例如在swarm集群上, 启动一个alpine镜像来执行ping 8.8.8.8命令

# docker service create --name ping-google alpine ping 8.8.8.8

9cyy6xrk2n0welrql49hm3ass

查询 swarm service列表, 我们可以看到刚刚创建的service:

# docker service ls

ID            NAME         REPLICAS  IMAGE   COMMAND

9cyy6xrk2n0w  ping-google  1/1       alpine  ping 8.8.8.8

docker service ps <Service ID or Name>命令可以查看服务到底跑在哪个节点服务器上:

# docker service ps ping-google

ID                         NAME               IMAGE   NODE    DESIRED STATE  CURRENT STATE           ERROR

alxkyacovh4ltiklpccjhf2u5  ping-google.1      alpine  node03  Running        Running 5 minutes ago

15e8v9q83wu3skrz63ieacbkr   \_ ping-google.1  alpine  node01  Shutdown       Rejected 5 minutes ago  "No such image: alpine:latest"

上面的输出我们可以看到service当前跑在node03上, 下面有一条node01上的报错是怎么回事呢?

hehe, 因为docker hub连接不稳的问题, 有时候你还可能没法pull到image.
swarm集群会不断帮你重试启动容器,直到成功为止,报错即为启动失败的日志。

2.3.1 扩展(Scale)服务
现在我们的ping-google服务只有一个容器, 注意下面的REPLICAS字段.

# docker service ls

ID            NAME         REPLICAS  IMAGE   COMMAND

9cyy6xrk2n0w  ping-google  1/1       alpine  ping 8.8.8.8

如果我们想Scale服务到10个副本容器, 可以使用

docker service scale <Service ID or Name>=<replicas No.>

# docker service scale ping-google=10

ping-google scaled to 10

# docker service ls

ID            NAME         REPLICAS  IMAGE   COMMAND

9cyy6xrk2n0w  ping-google  1/10      alpine  ping 8.8.8.8

注意REPLICAS现在显示1/10表示这个service一共有10个副本,现在成功运行了1个. 集群正在启动其他的副本.

这时候查看service进程:

# docker service ps ping-google

ID                         NAME                IMAGE   NODE    DESIRED STATE  CURRENT STATE               ERROR

alxkyacovh4ltiklpccjhf2u5  ping-google.1       alpine  node03  Running        Running about an hour ago

15e8v9q83wu3skrz63ieacbkr   \_ ping-google.1   alpine  node01  Shutdown       Rejected about an hour ago  "No such image: alpine:latest"

2x0abay1gtfdj2kposza0cwbc  ping-google.2       alpine  node03  Running        Running 13 seconds ago

evt8fdlph66e1ih9cayrhz1zg  ping-google.3       alpine  node05  Ready          Preparing 2 seconds ago

b9fciqvr90ruq1h0yoeudm54t   \_ ping-google.3   alpine  node05  Shutdown       Rejected 2 seconds ago      "No such image: alpine:latest"

10voxosxigfek1yd29u5o5igk   \_ ping-google.3   alpine  node05  Shutdown       Rejected 14 seconds ago     "No such image: alpine:latest"

57urifyyjzyqzjgbo8mpuuj3z  ping-google.4       alpine  node01  Running        Running 8 seconds ago

51ttvahuq54xrs64egx1gk4lx  ping-google.5       alpine  node01  Running        Running 11 seconds ago

288uy2wj5pw3gdu5texm1f9hl   \_ ping-google.5   alpine  node01  Shutdown       Rejected 18 seconds ago     "No such image: alpine:latest"

6fphqamttmmwztp43d3a2iz8q  ping-google.6       alpine  node02  Running        Preparing 13 seconds ago

82jd8lipbsc4x1i3msd6kqe0x   \_ ping-google.6   alpine  node02  Shutdown       Rejected 18 seconds ago     "No such image: alpine:latest"

3l5kv6zwh5nx4piqd983i39nr  ping-google.7       alpine  node05  Running        Preparing 9 seconds ago

bhvwas8un7xwplo4e0r3vv5z7   \_ ping-google.7   alpine  node05  Shutdown       Rejected 14 seconds ago     "No such image: alpine:latest"

64npet8ftxctdvbfjuqn3b7xs  ping-google.8       alpine  node02  Running        Preparing 11 seconds ago

2ydgrctk17btn1dplrc5z53tl   \_ ping-google.8   alpine  node02  Shutdown       Rejected 16 seconds ago     "No such image: alpine:latest"

alqhl7r3nmff0h1mrez9iw348  ping-google.9       alpine  node04  Running        Preparing 13 seconds ago

7facu0tsaqpxiwqwclpz4ir0n   \_ ping-google.9   alpine  node04  Shutdown       Rejected 18 seconds ago     "No such image: alpine:latest"

1mt8ucgdjxsxdozqtwclyp11w  ping-google.10      alpine  node04  Running        Preparing 11 seconds ago

e8om0kbqyn2r91v3oz72kx0tb   \_ ping-google.10  alpine  node04  Shutdown       Rejected 16 seconds ago     "No such image: alpine:latest"

-_-!!! 不忍直视…还是因为docker hub连接不稳定原因,pull image失败造成你会看到很多Error。忽略吧, swram集群会自动重试的…

等所有的副本都启动成功了, 你会看到swarm集群会自动编排10个副本到5台docker宿主机上,而且每个节点会启动2个容器。

# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS

b440806604e0        alpine:latest       "ping 8.8.8.8"      10 seconds ago      Up 8 seconds

6b217e23fee6        alpine:latest       "ping 8.8.8.8"      10 seconds ago      Up 8 seconds

2.3.2 开放一个服务端口

跟我们在单机使用docker一样, 你可以将你容器的端口暴露到主机网络中,从而使得跑在容器中的应用能够被外部访问。

swarm集群的service端口暴露还有如下特性:

  • 公共的端口会暴露在每一个swarm集群中的节点服务器上.
  • 请求进如公共端口后会负载均衡到所有的sevice实例上.

发布端口的参数跟单机环境一样是-p, 就是把docker run -p替换成docker service create -p就行。

下面我们创建一个elasticsearch服务, 发布9200端口:

# docker service create --name search --publish 9200:9200 --replicas 7 elasticsearch

使用以下命令监控 service 创建过程:

# watch docker service ps search

DESIRED STATE列, 一个service副本的创建过程,会经历以下几个状态:

  • accepted 任务已经被分配到某一个节点执行
  • preparing 准备资源, 现在来说一般是从网络拉取image
  • running
  • shutdown

当一个任务被终止stoped or killed.., 任务不能被重启, 但是一个替代的任务会被创建.

测试服务端口:

# curl localhost:9200

{

"name" : "Rachel Grey",

"cluster_name" : "elasticsearch",

"version" : {

"number" : "2.3.4",

"build_hash" : "e455fd0c13dceca8dbbdbb1665d068ae55dabe3f",

"build_timestamp" : "2016-06-30T11:24:31Z",

"build_snapshot" : false,

"lucene_version" : "5.5.0"

},

"tagline" : "You Know, for Search"

}

反复执行这个命令, 你会看到name会改变, 请求会被分发到不同的service副本.

2.3.3 删除服务

下一章我们要将docker币应用, 跑在swarm集群上,开始之前, 清理我们的service.

docker service rm <Service ID or Name>

删除所有servcie可以使用如下命令;

# docker service ls -q | xargs docker service rm

4iwtgcfnovd2uzcyp5w57qd0e

bnfutusm7qide08ihurxmucis