「伸手摘星,即使一无所获,亦不致满手污泥」。
「请关注公众号:星河之码」
一、Docker Swarm介绍
「Docker Swarm是Docker的集群管理工具,它提供了标准的Docker API,所有任何已经与Docker守护程序通信的工具都可以使用Swarm轻松地扩展到多个主机」。支持的工具包括Dokku、Docker Compose、Docker Machine和Jenkins等。
compose、machine 和 swarm 是docker 原生提供的三大编排工具,简称docker三剑客。其官网地址
https://docs.docker.com/engine/swarm/
「Docker Swarm 和 Docker Compose」
Docker Swarm 和 Docker Compose都是 Docker 官方容器编排项目
「Docker Compose 是一个在单个服务器或主机上创建多个容器的工具,可以将组成某个应该的多个docker容器编排在一起,同时管理」。

「Docker Swarm 则可以在多个服务器或主机上创建容器集群服务,其主要作用是把若干台Docker主机抽象为一个整体,并且通过一个入口(docker stack)统一管理这些Docker主机上的各种Docker资源」。

「docker stack」
docker stack 是构成特定环境中的 service 集合, 它是自动部署多个相互关联的服务的简便方法,而无需单独定 义每个服务。 stack file 是一种 yaml 格式的文件,类似于 docker-compose.yml 文件,它定义了一个或多个服务,并 定义了服务的环境变量、部署标签、容器数量以及相关的环境特定配置等。
Docker Swarm就是用来管理Docker集群的,但是现在基本上使用的很少,一般都是用的K8S,学习K8S之前可以先学习一个Docker Swarm,将其作为一个容器编排的一个学习基础,了解一下即可
二、Docker Swarm运行原理
Swarm集群由多个运行在swarm mode的docker主机组成,docker主机分为管理节点(manager)和工作节点(work node)两种类型
「管理节点(manager):负责整个集群的管理工作包括集群配置、服务管理,服务的创建和调度等」
「工作节点(work node):负责运行相应的服务来执行任务(运行容器服务)」
manager节点也可以运行的容器服务,但是一般不这么做,只是让它管理work node
Swarm集群的优点:
在线修改Service的配置,包括networks和volumes,不需要重启docker服务 可以将其它standalone模式的docker主机加入到Swarm集群
Standalone模式简单点说就是 manager 和 work 的一种管理关系模式
「在Docker Swarm中有几个基本概念:nodes、Service、tasks、load balancing」。需要简单了解一下
2.1 nodes
Node是加入到Swarm集群中的Docker实例,即是一个docker节点,包含上面说的【管理节点(manager)和工作节点(work node)】
在部署应用到Swarm集群的时候,会向管理节点提交service定义,管理节点会将这些这些work也就是tasks分发到work节点中。 Work节点接收并执行管理节点分配的任务,work节点也会将当前tasks的状态通知到管理节点以维护节点的状态信息。

「管理节点(manager node)」
「Manager节点主要通过raft算法实现整个集群和运行的service的内部状态维护,Docker官方建议一个集群最好使用基数manager节点数(最大使用7个manager节点)保证可用性」 ,Manager节点主要工作是完成以下tasks:
维护cluster state scheduling服务 service swarm mode集群服务 「工作节点(work node)」
Work节点是容器实际运行的实例节点,在默认情况下manager节点也是work节点,而且在在Swarm集群中必须存在manager节点
manager节点状态、信息的同步根据Raft consensus group(Raft一致性算法)的网络进行通信同步的,而worker之间的通信依靠的是Gossip network通信协议实现的。
「管理节点与工作节点的切换」
在多节点的Swarm集群中,节点有两种模式:【Active模式,Drain模式】。
「Swarm调度不会将任务分配到Drain模式,只会在Active模式的节点上分配任务。因此可以将manager节点设置为Drain模式(避免调度任务运行在manager节点,manager指做管理)」
docker node promote通过以上命令可以修改节点模式,将worker节点变为manager节点,也可以将manager节点转换为worker节点。
2.1 Service与tasks
「Service是manage和work节点上执行的task的定义,创建service的时候可以指定使用哪个container image以及执行的命令。」
「当Service部署到Swarm集群的时候,swarm管理节点会将service为标准(container image以及执行的命令),然后将service调度到集群的节点上,以一个或多个tasks执行」,这些nodes上运行的tasks之间是相互独立的。
「在replicated service模式下,swarm管理节点会根据desired state中设置的scale分发replica tasks」 「在globalservice模式,swarm集群会向每个可用的节点运行tasks」

如上service中有三个replicas tasks,每个实例是Swarm集群中的一个task。
「Task是Swarm集群中调度的最小单元,当创建或更新service时候给定了desired state,集群会调度tasks来实现这种理想状态」。
Task是一种单向机制,它整个周期过程中会完成一系列的状态(assigned、prepared和running等),tasks运行失败集群会remove这个tasks并创建新的tasks来替代。
2.1 load balancing
「负载均衡:Swarm集群使用ingress loading balancing提供集群服务,Swarm集群会自动为service分配PublishedPort,默认使用30000-32767范围」。
三、Docker-swarm安装部署
3.1 准备工作
「官方地址」
https://docs.docker.com/engine/swarm/「添加私服仓库地址」
由于官方镜像下载比较慢,由于网络原因可能拉取不下来,而集群的每个节点都需要安装镜像,所以使用私有仓库会快很多,当然也可以不使用私有仓库,直接自己下载上传。
#编辑配置文件
vi etc/docker/daemon.json
#增加仓库配置信息
# 在daemon.json中添加以下 key,保存退出。此步用于让 docker 信任私有仓库地址
{"insecure-registries":["192.168.242.130:5000"]}
#重新加载docker配置
systemctl daemon-reload
#重启docker
systemctl restart docker
3.2 docker-swarm安装
这里模拟安装集群,以三个节点搭建集群在加上一个Harbor节点,节点信息如下
| 节点 | Ip | 说明 |
|---|---|---|
| manager-01 | 192.168.242.131 | swarm-manager 节点 |
| work-01 | 192.168.242.132 | swarm-work节点 |
| work-02 | 192.168.242.133 | swarm-work节点 |
| harbor | 192.168.242.130 | harbor 私服 |
安装上述配置,克隆出相应的虚拟机,其中harbor之前已经存在,这里用之前的,所以一共克隆出三个服务器

「查看网络情况」
docker network ls
「初始化manager管理节点」
初始化manager管理节点完整命令如下
#这里使用192.168.242.131这台主机作为manager 所以以下命令在192.168.242.131上执行 端口默认是2377
docker swarm init --advertise-addr 192.168.242.131:2377 --listen-addr 192.168.242.131:2377执行上面命令后,就会初始化swarm集群,并且会告诉我们如何增加wrok 节点和manager节点

「再次查看网络情况」
#集群初始化后会新增集群网络
docker network ls
「--advertise-addr」:指定其他节点连接manager时的地址 「--listen-addr」:监控swarm集群manager的IP和端口 「语法」
docker swarm init参数说明
这个命令需要指定两个参数--advertise-addr 与--listen-addr
「查看节点」
docker node ls
「新加一个work节点」
通过上面初始化manager返回的命令,给集群加入新的节点,只需要在对应的主机上执行该命令即可
docker swarm join --token SWMTKN-1-55wujoaco7zp7kdvot57wu15drul4m3svoifnitz69r6jv2xyj-5o009d6f4oxlnahfwfzke5ukj 192.168.242.131:2377我在192.168.242.132这台主机上执行上述命令,将其加入到集群中

这个命令「本质上就是manager初始化的时候返回了一个token,其他主机通过这个token加入集群,并且token只有24小时」。如果失效,则需要重新获取
「重新获取token」
#获取一个worker加入集群的token
docker swarm join-token worker
「查看节点」
docker node ls
「新加一个manager节点」
一个集群要有多个manager节点,上面加入了work节点,接下来在集群中加入一个manager节点,加入方式一样的,先获取manager的token
「获取manager节点的token」
#获取一个manager加入集群的token ,这个命令要在之前的那个manager 192.168.242.131 上执行
docker swarm join-token manager
「加入集群」
这里就用 192.168.242.133 这个主机作为一个manager加入集群

3.3 swarm节点说明
「manager与work的权限」
「swarm集群中,只有manager节点可以执行swarm命令(比如docker node ls),work节点会报错,因为只有manager节点才可以管理集群,执行集群相关的命令」

work 节点只是不能执行swarm的集群命令,但是docker本身的命令是可以执行的,比如docker ps等
「查看节点信息」
可以分别在manager和node中查看节点的swarm信息,对比差异
docker info
「节点可用性与状态说明」
在使用docker node ls 命令查看集群的节点信息的时候,有两列需要注意一下:AVAILABILITY,MANAGER STATUS

「Leader:该节点是集群管理和编排决策的主要管理器节点。」 「Reachable:该节点是管理者节点正在参与Raft选举。如果Leader节点不可用,则该节点有资格被选为新领导者。」 「Unavailable:该节点属于不能与其他manager通信的manager。如果manager节点不可用,可以将它加入群集,或者将工作器节点升级为管理器」。 「Active:调度程序可以将任务分配给当前节点。」 「Pause:调度程序不会将新任务分配给当前节点,但现有任务仍在运行。」 「Drain:调度程序不会向当前节点分配新任务。调度程序关闭所有现有任务并在可用节点上重新调度这些任务。」 「AVAILABILITY」
决定当前节点可用性,是否用于运容器,它有三个值:
「改变节点的可用性(availability)」
docker node update --availability drain 节点Id/名称「MANAGER STATUS」
表示manger节点的状态,work节点为空,它也有三个状态值
3.4 集群节点管理
「节点权限提升/降低」
节点manager和work两种,他们的权限不一样,我们可以手动的对节点权限提升/降低,也是「将manager降级为work,将work升级为manager节点」。升级降级的命令都要在manager节点执行。
「将work升级为manager节点」
#将worker节点提升为manager节点,在manager节点执行如下命令:
docker node promote 节点名称|节点ID比如我将132 节点升级为manager节点

「将manager降级为work」
将manager节点降低为worker节点,在manager节点执行如下命令:
docker node demote 节点名称|节点ID
docker node ls将刚刚升级的132 节点重新降级为worker节点

「work脱离集群」
前面演示了怎么给集群中加入节点,现在来看看将节点脱离集群
#在要脱离集群的节点上使用一下命令, 主动离开集群,让节点处于down状态,才能删除
docker swarm leave
#指向完后,等一会在manager节点使用命令:docker node ls 就会发现该节点已经脱离集群管理这里我将132节点脱离集群

「删除脱离集群的节点」
上述节点脱离集群后,才能删除节点,删除节点使用如下命令
docker node rm 节点名称|节点ID
「manager脱离集群」
「manager节点不能脱离集群,使用docker swarm leave会报错」。

manager节点不能脱离集群,只能强制退出,manager退出后意味着整个swarm 不复存在。
#manager节点强制退出
docker swarm leave --force
3.5 Docker-swarm命令汇总
「swarm命令汇总」
命令 描述 docker swarm init 初始化一个 swarm 群集 docker swarm join 加入群集作为节点或管理器 docker swarm join-token 管理用于加入群集的令牌 docker swarm leave 离开 swarm 群集 docker swarm unlock 解锁 swarm 群集 docker swarm unlock-key 管理解锁钥匙 docker swarm update 更新 swarm 群集 「node命令汇总」
命令 描述 docker node demote 从 swarm 群集管理器中降级一个或多个节点 docker node promote 将一个或多个节点推入到群集管理器中(也就是升级节点) docker node inspect 显示一个或多个节点的详细信息 docker node ls 列出 swarm 群集中的节点 docker node ps 列出在一个或多个节点上运行的任务,默认为当前节点 docker node rm 从 swarm 群集删除一个或多个节点 docker node update 更新一个节点
四、图形界面
上述安装过程是通过命令行的方式安装docker-swarm,docker-swarm也提供了一个图形界面来操作,接下来就来安装一下docker-swarm的图形界面。
「docker-swarm的图形界面需要安装在manager节点上」,不然无法操作节点
#docker官网地址
https://hub.docker.com/r/dockersamples/visualizer
「拉取镜像」
docker pull dockersamples/visualizer:latest「备份镜像」
备份镜像有两种方式:私服和tar包。
「tar包」
镜像拉取下来之后,可以把它打成一个tar,保存起来,后面使用的时候直接还原即可,就不用下载了
#打成一个tar 包
docker save dockersamples/visualizer:latest -o dockersamples.visualizer.tar
#需要用的时候还原成镜像
docker load -i dockersamples.visualizer.tar「私服」
除了打成tar 存在本地之外,还可以将镜像上传私服,以后在私服拉取
# 1、标记镜像打一个tag
docker tag dockersamples/visualizer:latest 192.168.242.130:5000/edwinedu/dockersamples/visualizer:latest
# 2、上传标记的镜像 上传之前要先登录 docker login -u admin -p Harbor12345 192.168.242.130:5000
docker push 192.168.242.130:5000/edwinedu/dockersamples/visualizer:latest

「运行镜像」
# var/run/docker.sock 是必须要的挂载目录 HOST是指定Ip,需要是manager节点的Ip
docker run -itd --name visualizer -p 8099:8080 -e HOST=192.168.198.131 -e PORT=8080 -v var/run/docker.sock:/var/run/docker.sock 192.168.242.130:5000/edwinedu/dockersamples/visualizer:latest
「访问图形界面」
http://192.168.242.131:8099/
五、Docker-service
docker-service 是指一组任务的集合,服务定义了任务的属性,比如任务的个数、服务策略、镜像的版本号等,服务有两种模式:
replicated services:按照一定规则在各个工作节点上运行指定个数的任务 global services:每个工作节点上运行一个任务

接下来以Nginx为例,分别在几个节点上部署Nginx任务
5.1 Nginx基础镜像准备
「拉取Nginx镜像」
docker pull nginx:1.18.0-alpine「备份镜像」
由于要在每个节点都安装Nginx,所以需要在每个节点都下载镜像,当然可以使用私服下载,但是这里我不使用私服,练习一个scp命令
#打成一个tar 包
mkdir -p data/nginx
docker save nginx:1.18.0-alpine -o data/nginx/nginx:1.18.0.tar「传输镜像」
将nginx镜像使用scp 命令传输到192.168.242.132,192.168.242.132两个节点中
#执行下面命令之前,要确保132 133 两个节点有指定的目录 data/nginx
#注意nginx\:1.18.0.tar 中间有一个反斜杠
scp data/nginx/nginx\:1.18.0.tar root@192.168.242.132:/data/nginx
scp data/nginx/nginx\:1.18.0.tar root@192.168.242.133:/data/nginx
「解压nginx」
分别在所有节点中解压nginx (192.168.242.132,192.168.242.132两个节点)
cd data/nginx
docker load -i nginx:1.18.0.tar
5.2 部署Nginx
「创建nginx网络」
在manager节点中创建overlay网络
docker network create -d overlay nginx-net
「部署Nginx」
在集群中创建7个Nginx服务,在manager节点中执行,使用【docker service create】命令
# --network nginx-net 使用刚刚创建的网络
# replicas 7 代表 7个副本服务
docker service create --name nginx --network nginx-net -p 80:80 --replicas 7 nginx:1.18.0-alpine「界面查看」

manager节点也可以查看
docker service ls
「访问Nginx」
#三台主机都可以访问
http://192.168.242.131/80
http://192.168.242.132/80
http://192.168.242.133/80
「剔除manager中非服务」
前面说manager节点只用于管理集群,一般不部署服务,而在上面图形界面中显示,manager中有三个服务,如果要剔除,可以执行以下命令
docker node update --availability drain 节点Id|名称
「服务的缩容与扩容」
目前是在两个work中部署了7个nginx,如果要扩容与缩容,只需要修改service的数量就可以无感扩容与缩容,执行一下命令
#将nginx服务从七个减到5
docker service scale nginx=5
5.3 升级Nginx
在我们日常开发中,版本迭代是非常常见的,可能一周、一个月就迭代一个版本,那么版本迭代升级应该怎么做呢,接下来我们将nginx从1.18升级到1.19。
「查看nginx版本」
查看nginx版本可以通过容器查看,也可以通过界面查看
#通过容器查看版本,先进入容器中
docker exec -it 503fe639bb89 sh
nginx -v
#退出容器
exit
「准备nginx:1.19的镜像」
跟上面1.18的镜像一样,先在manager节点上拉取镜像,然后scp到132 133两台主机上,生产环境我们可以使用私服拉取镜像,不需要打包,这里只是练习scp命令
#拉取nginx:1.19.3-alpine镜像
docker pull nginx:1.19.3-alpine
#打成一个tar 包
mkdir -p data/nginx
docker save nginx:1.19.3-alpine -o data/nginx/nginx:1.19.3.tar
#执行下面命令之前,要确保132 133 两个节点有指定的目录 data/nginx
#注意nginx\:1.18.0.tar 中间有一个反斜杠
scp data/nginx/nginx\:1.19.3.tar root@192.168.242.132:/data/nginx
scp data/nginx/nginx\:1.19.3.tar root@192.168.242.133:/data/nginx
#分别在132 133 主机上执行解压1.19.3.tar
cd /data/nginx
docker load -i nginx:1.19.3.tar「升级Nginx」
在manager节点执行以下命令,将nginx从1.18.0-alpine升级到1.19.3-alpine
docker service update --image nginx:1.19.3-alpine nginx
「添加一个对外端口」
#将8090 也映射到容器的80端口
docker service update --publish-add 8090:80 nginx
5.4 删除Nginx服务
「删除service」
docker service rm nginx「删除之前创建的nginx-net」
docker network rm nginx-net
5.5 Docker-service命令汇总
| 命令 | 描述 |
|---|---|
| docker service create | 创建服务 |
| docker service inspect | 显示一个或多个服务的详细信息 |
| docker service logs | 获取服务的日志 |
| docker service ls | 列出服务 |
| docker service rm | 删除一个或多个服务 |
| docker service scale | 设置服务的实例数量 |
| docker service update | 更新服务 |
| docker service rollback | 恢复服务至update之前的配置 |
六、Docker-stack
6.1 Docker-stack的使用
「Stack是一组Service,和docker-compose类似,它也可以通过yml的将一组service放在一起操作,docker stack命令可以方便地操作一个Stack,而不用一个个地操作Service」。
默认情况下,一个Stack共用一个Network,相互可访问,与其它Stack网络隔绝
下面还是以上面的nginx集群为例,通过docker stack 来构建集群
「编写docker-stack.yml文件」
docker stack 文件的语法基本与docker-compose类似,
#版本写高一点,不支持 1 2
version: '3'
services:
edwin-nginx:
image: nginx:1.19.3-alpine
container_name: edwin-nginx
# 指定一个网络
networks:
- edwin-net
restart: always
ports:
- 80:80
deploy:
replicas: 7
# 创建nginx网络 networks中也可以不指定driver:overlay,因为docker swarm默认网络类型是overlay。
networks:
edwin-net:
driver: overlay「上传docker-stack.yml」
将docker-stack.yml上传到manager节点的/data/nginx目录下「启动镜像」
在manager节点中创建docker-stack.yml文件。执行如下命令:
#nginx-stack 是stack的名字
docker stack deploy nginx-stack --compose-file=docker-stack.yml
#或者是
docker stack deploy nginx-stack -c docker-stack.yml
「查看stack服务」
docker stack services nginx-stack「查看运行的节点」
查看7个nginx-stack容器分别运行在哪个节点中,可以通过以下命令
# 查看service的服务名为:nginx-stack_edwin-nginx
docker service ls
#查看7个nginx-stack容器分别运行在哪个节点中
docker service ps nginx-stack_edwin-nginx查看的前提是我们要修改各个主机的名字,不然都会显示localhost.localdomain

「修改主机名字」
# 第一步 在各个主机执行 docker-swarm-work-02 为当前主机要设置的主机名
hostnamectl set-hostname docker-swarm-manager-01
#第二步
vi /etc/hosts
# 将其中的 localhost.localdomain 替换成 docker-swarm-work-02
127.0.0.1 localhost docker-swarm-work-02 localhost4 localhost4.localdomain4
::1 localhost docker-swarm-work-02 localhost6 localhost6.localdomain6
#第三步 重启服务器
reboot
#第四步 查看hostname
hostname
分别按照上述步骤修改主机名字后,再次查看查看7个nginx-stack容器分别运行在哪个节点中,结果如下

「删除stack服务」
docker stack rm nginx-stack
6.2 docker-stack命令汇总
| 命令 | 描述 |
|---|---|
| docker stack deploy | 部署新的stack或更新现有stack |
| docker stack ls | 列出现有stack |
| docker stack ps | 列出stack中的任务 |
| docker stack rm | 删除一个或多个stack |
| docker stack services | 列出stack中的服务 |
6.2 Docker Stack和Docker Compose区别
Docker stack没有构建指令,无法使用stack命令构建新镜像,需要镜像是预先准备镜像。 docker-compose可以直接构建镜像,所以docker-compose更适合于开发场景; Docker Compose是Python写的,需要安装,Docker Stack是swarm mode的一部分,包含在Docker引擎中 Docker stack 不支持version版本为3以下的yml Docker stack 的功能基本上包含了docker compose。
七、Docker-Task
Task是 Swarm 集群中的最小的调度单位,任务包含一个Docker容器和在容器内运行的命令,如果某一个任务奔溃,那么协调器将创建一个新的副本任务,该任务将生成一个新的容器。

「Task调度主要分为Manager节点的任务分配和Worker节点的任务执行两部分」
「Manager节点的任务分配」 通过 Docker Engine Client 在manage节点使用命令 docker service create 提交 Service 定义 Manager节点根据定义创建相应的 Task,并分配IP地址 将Task分发到对应的节点上 节点进行相应的初始化使得它可以执行Task 「Worker节点的任务执行」 连接Manager节点的分配器检查该Task相关定义的信息 验证通过以后在 Worker 节点上执行Task
Task 的执行是一种单向机制,它会按顺序的依次经历 assigned, prepared 和 running 等执行状态,如果Task执行失败了,Manager的编排器会直接将该 Task 以及它的 Container 给删除掉,然后在其它节点上另外创建并执行该 Task





