1、Swarm 的概念
从主机层面来看,Docker Swarm 管理的是 Docker Host 集群。所以先来讨论一个重要的概念 - 集群化(Clustring)
服务器集群由一组网络上相互连接的服务器组成,它们一起协同工作。一个集群和一堆服务器最显著的区别在于:
集群能够像 单个 系统那样工作,同时提供高可用、负载均衡和并行处理。
如果我们部署应用和服务时选择的是多个独立的服务器而非集群,资源的整体利用率则很难达到最优,无法提前知道如何分布这些应用才能达到资源利用的最大化。而且,应用使用资源的趋势是波动的,例如早上某些服务可能需要大量的内存,而下午使用量就降下来了。提前指定应用应该运行在哪个服务器上会丧失业务的弹性,当某个服务器宕机了,我们不得不手工将受影响的应用迁移到其他服务器上。
实现集群化后我们的思维方式就必须改变了:不再考虑一个一个的服务器,而是将集群看做是一个整体。
部署应用时,我们只考虑需要多少内存和 CPU,而不是考虑会使用那台服务器的内存和 CPU。我们不应该关心应用会被部署在哪里,我们关心的是运行这个应用需要哪些资源,然后将它部署到集群,集群管理程序(比如 Docker Swarm)会搞定这些细节。
集群整体容量的调整是通过往集群中添加和删除主机节点实现的
我们会创建 Docker Swarm 集群、部署应用、伸缩扩展应用,以及对应用执行滚动升级。
Docker Swarm Mode
Docker v1.12 是一个非常重要的版本,Docker 重新实现了集群的编排方式。在此之前,提供集群功能的 Docker Swarm 是一个单独的软件,而且依赖外部数据库(比如 Consul、etcd 或 Zookeeper)。
从 v1.12 开始,Docker Swarm 的功能已经完全与 Docker Engine 集成,要管理集群,只需要启动 Swarm Mode。安装好 Docker,Swarm 就已经在那里了,服务发现也在那里了(不需要安装 Consul 等外部数据库)。
相比 Kubernetes,用 Docker Swarm 创建集群非常简单,不需要额外安装任何软件,也不需要做任何额外的配置。很适合作为学习容器编排引擎的起点。
重要概念 - swarm
swarm 是运行Docker Engine的多个主机组成的集群
从 v1.12开始,集群管理和编排功能已经集成到 Docker Engine 中。当Docker Engine 初始化了一个swarm 或者加入到一个存在的swarm时,他就会启动 swarm mode。
没启动 swarm mode 时,Docker 执行的是容器命令。运行swarm mode 后,Docker 增加了编排service的能力。
Docker 允许在同一个Docker Host 上即运行 swarm service,又运行单独的容器。
重要概念 - node
swarm 中的每个 Docker Engine 都是一个node,有两种类型的node:manager 和 worker 。
为了向swarm 中部署应用,我们需要在manager mode 上执行部署命令,manager node 会将部署任务拆解并分配给一个或者多个 worker node 完成部署。
manager node 负责执行编排和集群管理工作,保持并维护swarm 处于期望的状态。swarm中如果有多个manager node,他们会自动协商并选举出一个leader执行编排任务。
worker node 接受并执行由manager node 派发的任务。默认配置下manager node 同时也是一个 worker node,不过可以将其配置成manager-only mode,让其专职负责编排和集群管理工作。
worker node 会定期向manager node 报告自己的状态和他正在执行的任务状态,这样,manager 就可以维护整个集群的状态
重要概念 - service
service 定义了 worker node 上要执行的任务,swarm的主要编排任务就是要保证service 处于期望的状态下。
举一个 service 的例子: 在swarm 中启动一个http访问,使用的镜像是httpd:lastes,副本数是3
manager node 负责创建这个service ,经过分析指导需要启动3个httpd 容器,根据当前各worker node 的状态将运行容器的任务分配下去,比如worker1 上运行两个容器,worker2上运行一个容器。
运行了一段时间,worker2 突然宕机了,manager 监控到这个故障,于是立即在worker3 上启动了一个新的httpd容器。
这样就保证了 service 处于期望的三个副本状态。
2、创建swarm集群
本节我们将创建三节点的swarm集群(Docker 版本均不低于 v1.12)。
机器规划 | IP地址 | 机器名 |
worker1 | 192.168.1.109 | swarm-worker1 |
worker2 | 192.168.1.108 | swarm-worker2 |
manager | 192.168.1.107 | swarm-manager |
注意一定要关闭防火墙
[root@swarm-manager ~]# docker swarm init --advertise-addr 192.168.1.107
Swarm initialized: current node (9ggtulpdf9mr4x66o9defr56k) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-68h9qpnnpxz2xj2g9am3qarny464qkql21le7gfy75al68k4tx-c5pbru4o7ladzzqkrocnjz1a9 192.168.1.107:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
--advertise-addr 指定与其他 node 通信的地址。
docker swarm init 输出告诉我们:
① swarm 创建成功,swarm-manager 成为 manager node。
Swarm initialized: current node (9ggtulpdf9mr4x66o9defr56k) is now a manager.
② 添加 worker node 需要执行的命令。
docker swarm join --token SWMTKN-1-68h9qpnnpxz2xj2g9am3qarny464qkql21le7gfy75al68k4tx-c5pbru4o7ladzzqkrocnjz1a9 192.168.1.107:2377
③ 添加 manager node 需要执行的命令。
docker swarm join-token manager
执行 docker node ls 查看当前 swarm 的 node,目前只有一个 manager。
[root@swarm-manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
9ggtulpdf9mr4x66o9defr56k * swarm-manager Ready Active Leader 19.03.8
复制前面的 docker swarm join
命令,在 swarm-worker1 和 swarm-worker2 上执行,将它们添加到 swarm 中。命令输出如下:
[root@swarm-worker1 ~]# docker swarm join --token SWMTKN-1-68h9qpnnpxz2xj2g9am3qarny464qkql21le7gfy75al68k4tx-c5pbru4o7ladzzqkrocnjz1a9 192.168.1.107:2377
This node joined a swarm as a worker.
[root@swarm-worker2 ~]# docker swarm join --token SWMTKN-1-68h9qpnnpxz2xj2g9am3qarny464qkql21le7gfy75al68k4tx-c5pbru4o7ladzzqkrocnjz1a9 192.168.1.107:2377
This node joined a swarm as a worker.
docker node ls
可以看到两个 worker node 已经添加进来了。
[root@bogon ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
9ggtulpdf9mr4x66o9defr56k * swarm-manager Ready Active Leader 19.03.8
lw2jxibv485xttqjeyxjxjckw swarm-worker1 Ready Active 19.03.8
rdbwovw93wk3gb2yqjpipjgyd swarm-worker2 Ready Active 19.03.8
如果当时没有记录下 docker swarm init
提示的添加 worker 的完整命令,可以通过 docker swarm join-token worker
查看。
[root@swarm-manager ~]# docker swarm join-token worker #查看添加
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-68h9qpnnpxz2xj2g9am3qarny464qkql21le7gfy75al68k4tx-c5pbru4o7ladzzqkrocnjz1a9 192.168.1.107:2377
[root@swarm-manager ~]#
当时没有记录下 docker swarm init
提示的添加 manager 的完整命令,可以通过 docker swarm join-token manager
查看
[root@swarm-manager ~]# docker swarm join-token manager #查看添加
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-68h9qpnnpxz2xj2g9am3qarny464qkql21le7gfy75al68k4tx-c5pbru4o7ladzzqkrocnjz1a9 192.168.1.107:2377
[root@swarm-manager ~]#
注意:此命令只能在 manager node 上执行。至此,三节点的 swarm 集群就已经搭建好了
3、运行第一个 Service
现在部署一个运行 httpd 镜像的 service,执行如下命令:
docker service create --name web_server httpd
部署 service 的命令形式与运行容器的 docker run
很相似,--name
为 service 命名,httpd
为镜像的名字。
[root@swarm-manager ~]# docker service create --name web_server httpd
l8mfnq96k64b8kdgr0ldl93hr
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
[root@swarm-manager ~]#
通过 docker service ls
可以查看当前 swarm 中的 service。
[root@swarm-manager ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
l8mfnq96k64b web_server replicated 0/1 httpd:latest
[root@swarm-manager ~]#
REPLICAS
显示当前副本信息,0/1
的意思是 web_server 这个 service 期望的容器副本数量为 1,目前已经启动的副本数量为 0。也就是当前 service 还没有部署完成。命令 docker service ps
可以查看 service 每个副本的状态。1/1就表示创建完成 service 的运行副本数也正常了。
[root@swarm-manager ~]# docker service ps web_server
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
ccdy6hghlnxh web_server.1 httpd:latest swarm-manager Running Running 9 minutes ago
[root@swarm-manager ~]#
可以看到 service 唯一的副本被分派到 swarm-worker1,当前的状态是 Preparing
,还没达到期望的状态 Running
,我们不仅要问,这个副本在 Preparing 实际上是swarm-worker1 是在 pull 镜像,下载完成后,副本就会处于 Running
状态了 web_server运行在swarm-manager上
在swarm-manager上查看:
[root@swarm-manager ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
469db7f6ba21 httpd:latest "httpd-foreground" 8 minutes ago Up 8 minutes 80/tcp web_server.1.waibnto5emfgpmts8auksz6hi
[root@swarm-manager ~]#
docker service 命令只能在 swarm manager 上执行,在swarm worker 上执行会报如下错误
Error response from daemon: This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager.
4、实现 Service 伸缩
上节部署了一个副本,不过对于 web 服务,我们通常会运行多个实例。这样可以负载均衡,同时也能提供高可用。
swarm 要实现这个目标非常简单,增加 service 的副本数就可以了。在 swarm-manager 上执行如下命令:
[root@swarm-manager ~]# docker service scale web_server=5
web_server scaled to 5
overall progress: 5 out of 5 tasks
1/5: running [==================================================>]
2/5: running [==================================================>]
3/5: running [==================================================>]
4/5: running [==================================================>]
5/5: running [==================================================>]
verify: Service converged
[root@swarm-manager ~]#
副本数增加到 5,通过 docker service ls
和 docker service ps
查看副本的详细信息。
[root@swarm-manager ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
l8mfnq96k64b web_server replicated 5/5 httpd:latest
[root@swarm-manager ~]# docker service ps web_server
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
waibnto5emfg web_server.1 httpd:latest swarm-worker2 Running Running 31 minutes ago
wt8p6ogq9ufa web_server.2 httpd:latest swarm-worker1 Running Running 3 minutes ago
ep0b1ao3wob8 web_server.3 httpd:latest swarm-manager Running Running 3 minutes ago
8ot71f4dqcva web_server.4 httpd:latest swarm-manager Running Running 3 minutes ago
mf8f4mpm6udw web_server.5 httpd:latest swarm-worker2 Running Running 4 minutes ago
[root@swarm-manager ~]#
设置 swarm-manager 为仅manager模式:
docker node update --availability drain swarm-manager # 将 swarm-manager设置为仅 manager
[root@swarm-manager ~]# docker node update --availability drain swarm-manager # 将 swarm-manager设置为仅 manager
swarm-manager
docker node ls # swarm-manager AVAILABILITY 已经变成 Drain
[root@swarm-manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
9ggtulpdf9mr4x66o9defr56k * swarm-manager Ready Drain Leader 19.03.8
lw2jxibv485xttqjeyxjxjckw swarm-worker1 Ready Active 19.03.8
rdbwovw93wk3gb2yqjpipjgyd swarm-worker2 Ready Active 19.03.8
[root@swarm-manager ~]#
docker service ps web_server # 可以看到 swarm-manager 上的容器都已 shutdown,另外在work1上新起了两个容器
[root@swarm-manager ~]# docker service ps web_server
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
waibnto5emfg web_server.1 httpd:latest swarm-worker2 Running Running 37 minutes ago
wt8p6ogq9ufa web_server.2 httpd:latest swarm-worker1 Running Running 9 minutes ago
saisz4jtz9sl web_server.3 httpd:latest swarm-worker1 Running Running 2 minutes ago
ep0b1ao3wob8 \_ web_server.3 httpd:latest swarm-manager Shutdown Shutdown 2 minutes ago
wqmp99eqelhq web_server.4 httpd:latest swarm-worker1 Running Running 2 minutes ago
8ot71f4dqcva \_ web_server.4 httpd:latest swarm-manager Shutdown Shutdown 2 minutes ago
mf8f4mpm6udw web_server.5 httpd:latest swarm-worker2 Running Running 9 minutes ago
[root@swarm-manager ~]#
弹性收缩,将副本数由 5 降到 3
[root@swarm-manager ~]# docker service scale web_server=3
web_server scaled to 3
overall progress: 3 out of 3 tasks
1/3:
2/3: running
3/3: running
verify: Service converged
[root@swarm-manager ~]#
可以查看编号为4 和 5 的容器被删除了
[root@swarm-manager ~]# docker service ps web_server
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
waibnto5emfg web_server.1 httpd:latest swarm-worker2 Running Running 43 minutes ago
wt8p6ogq9ufa web_server.2 httpd:latest swarm-worker1 Running Running 16 minutes ago
saisz4jtz9sl web_server.3 httpd:latest swarm-worker1 Running Running 9 minutes ago
ep0b1ao3wob8 \_ web_server.3 httpd:latest swarm-manager Shutdown Shutdown 9 minutes ago