
我们在之前的学习都是操作一台主机上的一个或者多个容器,但是在实际场景中可能一个服务需要多台主机,多个容器,那这时候怎么办呢?
我们可以通过一套容器编排系统区解决。 Swarm Mode 并不是唯一可以做容器编排的工具 
Swarm是内置在Docker中的 

上面是Docker Swarm的结构设计,Docker Swarm是一种集群的架构,里面有各种节点,节点的角色分为Manager和Worker。 
Manager节点是整个Docker Swarm集群的大脑,至少有两个。 
当存在多个Manger的时候就需要涉及到同步(通过一个Manager做的事情如何同步到另一个Manager上?)同步使用到了一个内置的分布式存储的数据库,这个数据库是通过Raft协议进行同步。Raft协议能够确保Manager节点之间的信息数据是对称的,同步的,防止脑裂情况发生。 
Worker节点实际上就是干活的节点,大部分容器部署到集群中都会运行在Worker节点上。(Manager也是可以运行干活的,但是大部分还是运行在Worker上,因为Worker的节点比较多一点)Worker节点之间通过Gossip network进行信息同步。 

docker swarm中,service的概念和docker compose中的service概念是差不多的。一个service其实就代表了一个容器。 
replicas是在service的基础上做横向扩展,例如,一个nginx的swevice中有三个nginx的容器,其中每一个容器就可以理解为一个replica。 
swarm中通过manager节点去部署一个service的时候,我们事先是不知道这个service最终会运行在哪些swarm的cluster节点上的,swarm的scheduler会根据一定的调度算法去计算(比如会根据每台cluster节点的资源使用率等),将容器调度在相应的节点上。 
任务 (Task)是 Swarm 中的最小的调度单位,目前来说就是一个单一的容器。 
服务 (Services) 是指一组任务的集合,服务定义了任务的属性。 
服务有两种模式:
- replicated services按照一定规则在各个工作节点上运行指定个数的任务。
- global services强制在每个- node上都运行一个且最多一个容器。

上图是Docker Swarm创建Service的调度过程。 
我们在Swarm Manager做决策,最终结果要把Service部署到哪个Node上面,然后执行实际操作。 
创建一个三节点的Swarm的集群
我们使用play-with-docker创建三台主机

我们将192.168.0.48这台作为Manager其他两台作为Worker 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
查看初始化Swarm的参数 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
初始化的时候 通过advertise-addr来宣告本地地址的存在 
初始化创建一个Swarm集群
| 1 | [node1] (local) root@192.168.0.48 ~ | 
我们执行这个命令,来启用 swarm,我们当前主机作为管理节点 
它还创建了 swarm 根证书,还创建了 join token,用来让其他节点加入这个 Swarm 
还创建了 raft 数据库。 
我们在剩下的两台机子上执行加入集群的命令
| 1 | [node2] (local) root@192.168.0.47 ~ | 
| 1 | [node3] (local) root@192.168.0.46 ~ | 
\1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
\```powershell 
查看当前集群的节点有哪些`docker node ls` 
```powershell 
[node1] (local) root@192.168.0.48 ~ 
$ docker node ls 
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERS 
ION 
tmcx3ft8twi83tigoxqcflbgm * node1 Ready Active Leader 19.03.4 
ffv6izyiia3zrvtdg6n4efaz5 node2 Ready Active 19.03.4 
hvz2ylt57ann8uvad0un2001f node3 Ready Active 19.03.4
Service的创建维护和水平扩展
创建service
创建Service类似单机创建Docker,但是具体Service是部署到哪个节点是不一定的。 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
| 1 | $ docker service create | 
创建一个demo的Service 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
查看已有的service使用docker service ls: 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
通过上面的信息我们不知道demo这个服务的容器运行在哪一台服务器上,但是,可以通过docker service ps service_name来查看: 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
可以发现,demo这个service运行在node1这个管理节点上。 
这里的MODE为replicated表示是可以水平扩展的 
在node1节点上通过`docker ps查看: 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
service 扩展
我们看到有一个容器,名字为demo.1.mcewsjl5ekuwzr07sbveix3iy 
我们通过之前的demo这个service可以看到有一个REPLICAS显示的是1/1,这就说明demo这个service是可以横向扩展的,service的扩展类似于docker compose。也是通过参数scale来实现: 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
进行扩展
| 1 | [node1] (local) root@192.168.0.48 ~ | 
查看demo服务 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
可以发现REPLICAS已经由1/1变成了5/5。 
分母的5表示scale是5,分子是指多少是准别就绪的 
再次查看这5个容器分别运行在哪些节点之上:
| 1 | [node1] (local) root@192.168.0.48 ~ | 
我们看到容器变成了5个,并且是平均分配到各个节点上。
通过docker swarm scale创建的横向扩展(比如scale demo=5),那么,无论在哪个节点上强制删除其中一个或者多个该service的容器(dockerd服务必须在运行),docker swarm scale都会自动在当前的集群中的其他容器重新启动相应个数的容器,保持scale指定的数量。这样就可以确保系统稳定,不会出现业务停止的情况。 
在一个Worker节点上删除一个容器 
| 1 | [node2] (local) root@192.168.0.47 ~ | 
在Manager节点上面查看 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
我们看到会先变成4/5然后重新变为5/5 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
删除service
删除一个service只需要通过docker service rm service_name即可,在删除service之后,docker swarm会自动从当前swarm集群中删除该服务之前运行的所有容器(有一定的延时): 
| 1 | [node1] (local) root@192.168.0.48 ~ | 
参考文章:
