Docker Swarm群集部署
Docker自诞生以来,其容器特性以及镜像特性给DevOps爱好者带来诸多方便。然而在很长一段时间内,Dock”只能在单机上运行,其跨主机部署、运行与管理能力颇受外界诟病。跨主机能力薄弱,导致Docker容器与主机的形成高度耦合,降低了Docker容器的灵活性,难以实现容器的迁移、分组等功能。
案例概述
创鑫公司给云计算工程师提出新的要求,可将集群中所有Docker Engine整合进一个虚拟的资源池,通过执行命令与单一的主Swarm进行沟通,而不必分别和每个DockerEngine沟通。在灵活的调度策略下,T团队可以更好地管理可用的主机资源,保证应用容器的高效运行。
案例前置知识点
1.Docker Swarm概述
Docker Swarm是Docker社区提供的基于Docker的集群管理调度工具,能够将多台主机构建成一个Docker集群,用户通过API来管理多个主机上的Docker,并结合Overlay网络实现容器的调度与相互访问。
Docker Swarm默认对外提供两种API。
标准的Docker APl:包括Docker Client、Dokku、Compose、DockerUl、Jenkins等,它们可以通过Swarm工具与Docker集群进行通信;
集群管理AP:用于集群的管理。
2.基本特性
Docker集群管理和编排的特性是通过SwarmKit进行构建的,其中Swarm模式是Docker Engine内置支持的一种默认实现。Docker1.12以及更新的版本,都支持Swarm模式。用户可以基于Docker Engine构建Swarm集群,然后就可以将应用服务(ApplicationService)部署到Swarm集群中。
Docker Swarm具有如下基本特性:
集群管理集成进Docker Engine:使用内置的集群管理功能,可以直接通过Docker CLI命令来创建Swarm集群,并部署应用服务,而不需要其它外部软件来创建和管理Swarm集群。
去中心化设计:Swarm集群中包含管理节点(Manager)和工作节点(Norker)两类,可以直接基于Docker Engine来部署任何类型的节点。在Swarm集群运行期间,可以对其作出任何改变,实现对集群的扩容和缩容等,如添加与删除节点。而做这些操作时不需要暂停或重启当前的Swarm集群服务。
声明式服务模型:在实现的应用栈中,Docker Engine使用了一种声明的方式,可以定义各种所期望的服务状态。
缩放:对于每个服务,可以声明要运行的任务数。向上或向下扩展时,Swarm集群会通过添加或删除任务来自动调整以维持所需的状态。
协调预期状态与实际状态的一致性:管理节点会不断地监控并协调集群的状态,使得Swrm集群的预期状态和实际状态保持一致。例如启动一个应用服务,指定服务副本为10,则会启动10个Docker容器去运行。如果某个工作节点上面运行的2个Docker容器挂掉了,管理节点会在Swarm集群中其它可用的工作节点上创建2个服务副本,使得实际运行的Docker容器数保持与预期的10个一致。
多主机网络:Swarm集群支持多主机网络,可以为服务指定覆盖网络。管理节点在初始化或更新应用程序时自动为覆盖网络上的容器分配地址。
服务发现:管理节点会给Swarm集群中每一个服务分配一个唯一的DNS名称,对运行中的Docker容器进行负载均衡。可以通过Swarm内置的DNS服务器,查询Swarm集群中运行的Docker容器状态。
负载均衡:在Swarm集群中,可以指定如何在各个Node之间分发服务容器(ServiceContainer),实现负载均衡。如果想要使用Swarm集群外部的负载均衡器,可以将服务容器的端口暴露到外部。
默认安全:Swarm集群中的每个节点都强制执行TLS相互身份验证和加密,以保护自身与所有其他节点之间的通信。用户可以选择使用自签名根证书或自定义根CA的证书。
滚动更新:对于服务需要更新的场景,可以在多个节点上进行增量部署更新,在Swarm管理节点使用Docker CLI设置一个delay(延迟)时间间隔,实现多个服务在多个节点上依次进行部署,这样可以非常灵活地控制。如果有一个服务更新失败,则暂停后面的更新操作,重新回滚到更新之前的版本。
3.关键概念
下面是Docker Swarm中主要的关键概念。
(1)节点
每个参与到Swarm集群中的Docker Engine都称之为一个节点。在单个物理计算机或云服务器上运行一个或多个节点,但是生产环境下的集群部署通常包括分布在多个物理和云机器上的Docker节点。集群中节点主要分为管理节点与工作节点。
若要将应用程序部署到集群中,则需要将服务定义提交给管理节点。管理节点将被称为任务的工作单元分派给工作节点。为了维持Swarm集群的目标状态,管理节点还将承担编排和集群管理的功能。一旦存在多个管理节点时,会选出一个领导来进行任务编排。
工作节点用于接收并执行来自管理节点分发的任务。默认情况下,管理节点也是工作节点,也可以把它配置成只充当管理节点的角色。工作节点将所负责任务的当前状态通知给管理节点,以便管理节点可以维护每个工作节点的期望状态。
(2)服务与任务
服务定义了需要在工作节点上执行的任务。它是Swarm系统的中心结构,也是用户和Swarm交互的主要根源。
创建服务时,可以指定要使用的容器镜像以及在运行容器中执行的命令。在复制服务模型中,Swarm管理器根据所需状态中设置的比例在节点之间分配特定数量的副本任务。
任务是Swarm集群中最小的调度单位,每个任务都包含一个容器和需要在容器中执行的指令。管理器根据服务中定义的副本数量将任务分配给工作节点。一旦某个任务被分配到某个节点,就不能再移动到其他节点。它只能在分配的节点上运行或者失败。
(3)负载均衡
集群管理器使用负载均衡入口来公开对外提供的服务。集群管理器可以自动为PublishedPort(对外发布的端口)分配服务,也可以为服务配置PublishedPort。部署服务时可以指定任何未使用的端口为服务端口;如果部署服务时未指定端口,Swarm管理器会为服务自动分配30000-32767范围内的端口。
外部组件(例如云负载均衡器)可以访问集群中任何节点的PublishedPort上的服务,无论该节点当前是否正在运行该服务的任务。集群中的所有节点都将入口连接到正在运行的任务实例。
Swarm模式有一个内部DNS组件,可以自动为Swarm中的每个服务分配一个DNS条目。集群管理器使用内部负载均衡来根据服务的DNS名称在集群内的服务之间分发请求。
4.工作原理
在Swarm集群中部署镜像创建一个服务时。在一些大的应用上下文环境中需要各种服务配合工作,这样的服务通常称之为微服务。微服务可能是一个HTTP服务器、数据库、或者分布式环境中运行的任何其他可执行的程序。
在创建服务时,可以指定要使用的容器镜像以及容器中要运行的命令。服务还可以定义下面选项:
- 集群要对外服务的端口;
- 在集群中用于服务之间相连的Overlay网络;
- 滚动更新策略;
- 集群总运行的副本数量。
下面从以下几个方面具体介绍服务、任务与容器的具体工作方法。
(1)服务、任务与容器
当服务部署到集群时,Swarm管理节点会将服务定义作为服务所需状态。然后将服务调度为一个或多个副本任务。这些任务在集群节点上彼此独立运行。
容器是一个独立的进程。在Swarm集群中,每个任务都会调用一个容器。一旦容器运行,调度程序认为该任务处于运行状态。如果容器健康监测失败或者终止,那么任务也终止。
(2)任务与调度
任务是集群内调度的原子单位。当创建或者更新服务来声明所需的服务状态时,协调器通过调度任务来实现所需的状态。
任务是单向的机制,它通过一系列状态单独进行:分配、准备、运行等操作。如果任务失败,协调器将删除任务与容器,然后根据服务指定的所需状态创建一个新的任务来代替它。
(3)待处理的服务
配置服务时,若集群中当前没有可用的节点。在这种情况下,也可以成功配置服务,但所配置服务会处于待处理状态(挂起状态)。以下是服务可能处于待处理状态的几个示例。如果在集群中所有节点被暂停或耗尽时,创建了一个服务,服务则被挂起,直到节点可用。实际上,当节点恢复时,第一个可用的节点将会获得所有的任务,这在生产环境中并不是一件好事。
配置服务时可以为服务预留特定数量的内存。如果集群中没有节点满足需的内存量,服务则被挂起,直到有可用的节点运行其任务。如果指定了非常大的内存值(如500G),任务将永久挂起,除非确实有一个满足该条件的节点。
配置服务时可以对服务施加约束,并且可能无法在给定时间履行约束,服务则被挂起。
(4)副本和全局服务
服务部署分为两种类型:副本服务和全局服务。
副本服务:指定要运行的相同任务的数量,每个副本都是相同的内容。
全局服务:是在每个节点上运行一个任务的服务。不需要预先指定任务数量。每当将一个节点添加到集群中,调度器将创建一个任务,并且调度器将任务分配给新加入的节点。全局服务最好是监控代理、反病毒扫描程序等等想要在集群中每个节点上运行的容器。
部署
一:安装Docker
二:基础环境配置
1:设置主机名
(1)manager主机
[root@localhost ~]# hostnamectl set-hostname manager
[root@localhost ~]# bash
(2)worker01主机
[root@localhost ~]# hostnamectl set-hostname worker01
[root@localhost ~]# bash
(3)worker02主机
[root@localhost ~]# hostnamectl set-hostname worker02
[root@localhost ~]# bash
2:修改所有主机的hosts文件
[root@manager ~]# vim /etc/hosts
192.168.10.101 manager
192.168.10.102 worker01
192.168.10.103 worker02
3:设置所有主机的firewalld防火墙(如果防火墙关闭,可不用设置)
[root@manager ~]# firewall-cmd --zone=public --add-port=2377/tcp --permanent
[root@manager ~]# firewall-cmd --zone=public --add-port=7946/tcp --permanent
[root@manager ~]# firewall-cmd --zone=public --add-port=7946/udp --permanent
[root@manager ~]# firewall-cmd --zone=public --add-port=4789/tcp --permanent
[root@manager ~]# firewall-cmd --zone=public --add-port=4789/udp --permanent
[root@manager ~]# firewall-cmd --reload
firewall-cmd --zone=public --add-port=2377/tcp --permanent
firewall-cmd --zone=public --add-port=7946/tcp --permanent
firewall-cmd --zone=public --add-port=7946/udp --permanent
firewall-cmd --zone=public --add-port=4789/tcp --permanent
firewall-cmd --zone=public --add-port=4789/udp --permanent
firewall-cmd --reload
三:部署 Docker Swarm 集群
1:在manager主机上创建 Docker Swarm 集群
[root@manager ~]# docker swarm init --advertise-addr 192.168.10.101
Swarm initialized: current node (x3v12rmfw9c0isq1nppaaoogh) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-6d54xvraob3ea6peasvp5pgrtqp2f83vlfm7ag9q8ra6x1jqz3-1r93r88x483n7ofx96qj0cvjk 192.168.10.201:2377
2:在所有worker节点加入集群
[root@worker01 ~]# docker swarm join --token SWMTKN-1-6d54xvraob3ea6peasvp5pgrtqp2f83vlfm7ag9q8ra6x1jqz3-1r93r88x483n7ofx96qj0cvjk 192.168.10.201:2377
[root@worker02 ~]# docker swarm join --token SWMTKN-1-6d54xvraob3ea6peasvp5pgrtqp2f83vlfm7ag9q8ra6x1jqz3-1r93r88x483n7ofx96qj0cvjk 192.168.10.201:2377
3:查看集群信息
[root@manager ~]# docker info
........
Swarm: active
NodeID: x3v12rmfw9c0isq1nppaaoogh
Is Manager: true
ClusterID: 0mps950k70s2oqphe75jzykqq
Managers: 1
Nodes: 3
........
4:查看 Swarm 集群中 Node 节点的详细状态信息
[root@manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
x3v12rmfw9c0isq1nppaaoogh * manager Ready Active Leader 20.10.1
mripmqlv2rw84xzywaclvqolj worker01 Ready Active 20.10.1
gxxa4apflvapwcygvdgy0mdvh worker02 Ready Active 20.10.1
查看 manager 节点详细信息:docker node inspect manager
查看 worker01 节点详细信息:docker node inspect worker01
查看 worker02 节点详细信息:docker node inspect worker02
四:Docker Swarm 节点管理
1:将管理节点的 AVAILABILITY 值修改为 Drain 状态,使其只具备管理功能
[root@manager ~]# docker node update --availability drain manager
manager
[root@manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
rerfkmyfkbc74a04x22tpfo5j * manager Ready Drain Leader 19.03.9
irwxgrg6o8l69b6i024rkbury worker01 Ready Active 19.03.9
j7yit1q52486uhonee8jmhwgo worker02 Ready Active 19.03.9
注意:
节点的 AVAILABILITY 有三种状态:Active、 Pause、Drain。
Active:集群中该节点可以被指派任务。
Pause:集群中该节点不可以被指派新的任务,但是其他已经存在的任务保持运行。
Drain:集群中该节点不可以被指派新的任务,Swarm Scheduler 停掉已经存在的任务,并将它们调度到可用的节点上
2:添加标签元数据
- 支持给每个节点添加标签元数据
- 根据标签可选择性地调度某个服务部署到期望的一组节点上
[root@manager ~]# docker node update --label-add group=g2 worker01
[root@manager ~]# docker node inspect worker01
[root@manager ~]# docker service create --name mynginx --constraint 'node.labels.group==g2' nginx
备注:
constraint 约束
查看mynginx容器所在的主机
[root@manager ~]# docker service ps mynginx
3:节点提权/降权
将 worker01 和 worker02 都升级为管理节点
[root@manager ~]# docker node promote worker01 worker02
[root@manager ~]# docker node ls
对上面已提权的 worker01 和 worker02 执行降权操作
[root@manager ~]# docker node demote worker01 worker02
4:退出 Swarm 集群
[root@manager ~]# docker swarm leave
Error response from daemon: You are attempting to leave the swarm on a node that is participating as a manager. Removing the last manager erases all current state of the swarm. Use `--force` to ignore this message.
注意:
如果集群中还存在其它的工作节点,同时希望管理节点退出集群,则需要加上一个强制
选项
[root@manager ~]# docker swarm leave --force
Node left the swarm.
在work节点上退出swarm
[root@worker01 ~]# docker swarm leave
注意:
工作节点退出集群后通过 docker swarm join 命令并指定对应的 token 值重新加入集群。
如果管理节点也推出了群,需要在管理节点上使用docker swarm init --advertise-addr 192.168.10.201命令再生成一次群,其他节点再加入一次群即可,相当于重新创建一次群集
主要:
集群解散后,swarm创建的service会被删除掉
五:Docker Swarm 服务管理
创建好swarm群集
1:创建服务
(1)使用 docker service create 命令创建 Docker 服务,从 Docker 镜像 nginx 创建一个名称为 web 的服务,指定服务副本数为 2。
[root@manager ~]# docker service create -p 80:80 --replicas 2 --name web nginx
[root@manager ~]# docker service logs -f web
注意:
看到提示 Configuration complete; ready for start up后,可以Ctrl+C
(2)查看当前已经部署启动的全部应用服务
[root@manager ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
zgxqdeu3dph2 web replicated 2/2 nginx:latest
(3)可以查询指定服务的详细信息。
[root@manager ~]# docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
nc0lvzyt6fv8 web.1 nginx:latest worker01 Running Running 4 minutes ago
rknekib3x3eg web.2 nginx:latest manager Running Running 4 minutes ago
[root@manager ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
305d6fe1e1e4 nginx:latest "/docker-entrypoint.…" 5 minutes ago Up 5 minutes 80/tcp web.2.rknekib3x3egb9atn4qxub8nj
2:显示服务详细信息
(1)以 JSON 格式显示方法 Web 服务的详细信息
[root@manager ~]# docker service inspect web
(2)以易于阅读方式显示 Web 服务的详细信息
[root@manager ~]# docker service inspect --pretty web
3:服务的扩容缩容
(1)将前面已经部署的 2 个副本的 Web 服务,扩容到 3 个副本
[root@manager ~]# docker service scale web=3
(2)通过 docker service ps web 命令查看服务扩容结果
[root@manager ~]# docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
nc0lvzyt6fv8 web.1 nginx:latest worker01 Running Running 10 minutes ago
rknekib3x3eg web.2 nginx:latest manager Running Running 10 minutes ago
oxrqtrsuswcr web.3 nginx:latest worker02 Running Running 13 seconds ago
(3)缩容5
进行服务缩容操作时只需要设置副本数小于当前应用服务拥有的副本数即可,大于指定缩容副本数的副本会被删除
[root@manager ~]# docker service scale web=1
web scaled to 1
overall progress: 1 out of 1 tasks
1/1: running
verify: Service converged
[root@manager ~]# docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
nc0lvzyt6fv8 web.1 nginx:latest worker01 Running Running 11 minutes ago
4:删除服务
[root@manager ~]# docker service rm web
5:滚动更新
[root@manager ~]# docker service create --replicas 3 --name redis --update-delay 10s redis:3.0.6
[root@manager ~]# docker service ps redis
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
9dtcqqyptmbn redis.1 redis:3.0.6 manager Running Running 3 minutes ago
p4agvfmprmgm redis.2 redis:3.0.6 worker01 Running Running 3 minutes ago
vqo6493g9cws redis.3 redis:3.0.6 worker02 Running Running 3 minutes ago
更新已经部署服务所在容器中使用的镜像版本
[root@manager ~]# docker service update --image redis:3.0.7 redis
6:添加自定义 Overlay 网络
在创建服务时,通过--network选项指定使用的网络为已存在的 Overlay 网络
[root@manager ~]# docker network create --driver overlay my-network
[root@manager ~]# docker service create --replicas 3 --network my-network --name myweb nginx
备注:
如果 Swarm 集群中其他节点上的 Docker 容器也使用 my-network 网络,那么处于该
Overlay 网络中的所有容器之间都可以进行通信
7:数据卷创建与应用
(1)创建数据卷
[root@manager ~]# docker volume create product-kgc
(2)将nginx容器连接到数据卷
[root@manager ~]# docker service create --mount type=volume,src=product-kgc,dst=/usr/share/nginx/html --replicas 1 --name kgc-web-01 nginx
[root@manager ~]# docker service ps kgc-web-01
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
58g31r3ppwid kgc-web-01.1 nginx:latest worker01 Running Running 24 seconds ago
注意:
要确定好容器是在哪个节点运行的,可以看出,此案例中实在work01中运行的
(3)查看数据卷
[root@manager ~]# docker volume inspect product-kgc
[
{
"CreatedAt": "2021-01-24T09:19:33+08:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/product-kgc/_data",
"Name": "product-kgc",
"Options": {},
"Scope": "local"
}
]
(4)到work01中查看数据是否进行同步
[root@worker01 ~]# cd /var/lib/docker/volumes/product-kgc/_data/
[root@worker01 _data]# mkdir test01 test02
[root@worker01 _data]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8875962fb67b nginx:latest "/docker-entrypoint.…" 16 minutes ago Up 16 minutes 80/tcp kgc-web-01.1.58g31r3ppwidwi7x4m8vdy14y
41fdf50c16c2 nginx:latest "/docker-entrypoint.…" 17 minutes ago Up 17 minutes 80/tcp myweb.1.m89ipfy43w38n5f0qtckq55gb
4aa3abe80967 redis:3.0.7 "docker-entrypoint.s…" 18 minutes ago Up 18 minutes 6379/tcp redis.2.mczchtpy4uy7i52tyycwjd9uk
[root@worker01 _data]# docker exec -it 8875962fb67b bash
root@8875962fb67b:/# ls /usr/share/nginx/html/
50x.html index.html test01 test02
8:使用 bind 类型挂载数据卷
(1)创建测试目录
[root@manager ~]# mkdir -p /var/vhost/www/aa
[root@worker01 ~]# mkdir -p /var/vhost/www/aa
[root@worker02 ~]# mkdir -p /var/vhost/www/aa
在manager节点安装nfs-utils
[root@manager ~]# yum -y install nfs-utils
设置nfs共享
[root@manager ~]# vim /etc/exports
/var/vhost/www/aa *(rw,sync,no_root_squash)
启动nfs服务
[root@manager ~]# systemctl start nfs
[root@manager ~]# systemctl start rpcbind
在其他work节点挂载
yum -y install nfs-utils
mount 192.168.10.101:/var/vhost/www/aa /var/vhost/www/aa/
(2)创建 2 个 kgc-web-02 服务
[root@manager ~]# docker service create --replicas 2 --mount type=bind,src=/var/vhost/www/aa,dst=/usr/share/nginx/html/ --name kgc-web-02 nginx
(3)验证数据是否同步
[root@worker01 _data]# touch /var/vhost/www/aa/mytest
[root@worker01 _data]# docker service ps kgc-web-02
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
toejwbvg8nau kgc-web-02.1 nginx:latest manager Running Running 2 minutes ago
kv04aj4vt84g kgc-web-02.2 nginx:latest worker02 Running Running 2 minutes ago
[root@worker01 _data]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d292452b1f39 nginx:latest "/docker-entrypoint.…" 57 seconds ago Up 56 seconds 80/tcp kgc-web-02.1.toejwbvg8nau452rvexc0i1c9
6360a54d2bd1 nginx:latest "/docker-entrypoint.…" 22 minutes ago Up 22 minutes 80/tcp myweb.3.51xngm6q6zj9jo4vllohbptqn
930b56c8671c redis:3.0.7 "docker-entrypoint.s…" 23 minutes ago Up 23 minutes 6379/tcp redis.1.o2regcre7k626suqytpmqpidi
ada092f9959f redis:3.0.6 "/entrypoint.sh redi…" 27 minutes ago Exited (0) 23 minutes ago redis.1.9dtcqqyptmbnybz1ub3wfzuzj
[root@worker01 _data]# docker exec -it d292452b1f39 bash
root@d292452b1f39:/# ls /usr/share/nginx/html/
mytest