我们在之前的学习都是操作一台主机上的一个或者多个容器,但是在实际场景中可能一个服务需要多台主机,多个容器,那这时候怎么办呢?
我们可以通过一套容器编排系统区解决。 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 ~ |
参考文章: