Docker Swarm是管理跨节点容器的编排工具,相较于Docker Compose而言,Compose只能编排单节点上的容器,Swarm将一群Docker节点虚拟化为一个主机,使得用户只要在单一主机上操作就能完成对整个容器集群的管理工作。
准备工作
准备三个节点,要求实现奇数个节点
192.168.2.1 ————作为manager
192.168.2.2 ————作为node1
192.168.2.3 ————作为node2
三个节点在同一个网段,确保相互之间可以ping通
安装Docker-Engine
查看是否安装成功
[root@manager ~]# docker --version
Docker version 20.10.17, build 100c701
[root@manager ~]# docker compose version
Docker Compose version v2.6.0
节点管理
如下图所示,swarm 集群由管理节点(manager)和工作节点(work node)构成。
- swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
- work node:即图中的 available node,主要负责运行相应的服务来执行任务(task)
在创建集群之前,使用docker node ls
想查看下集群中节点的信息,反馈目前没有节点信息,并且当前节点并不是manager
[root@manager ~]# docker node ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
创建一个Swarm
在创建集群之前,使用docker node ls
想查看下集群中节点的信息,反馈目前没有节点信息,并且当前节点并不是manager
[root@manager ~]# docker node ls
Error response from daemon: This node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again.
创建新的集群
docker swarm init --advertise-addr 192.168.2.1
示例:
[root@manager ~]# docker swarm init --advertise-addr 192.168.2.81
Swarm initialized: current node (44qw5hbq836fryftoc51pnlbn) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-5d47eim8blk5jh37ww2eua7ve0r3u4w106j7oaoxuf4ilva0tw-cyl00cwc71rp0jfp59eyfhp4x 192.168.2.81:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
docker swarm join-token manager
命令用于获取添加新的 Manager Node 的命令参数
docker swarm join-token worker
命令用于获取添加新的 Worker Node 的命令参数
加入Swarm
可以在其它节点上执行docker swarm join --token......
来将该节点设置为工作node,并加入到这个swarm集群中
目前演示的是一个manager
,两个工作node的模式,所以在node1
和node2
上执行第一个命令即可:
docker swarm join --token SWMTKN-1-5d47eim8blk5jh37ww2eua7ve0r3u4w106j7oaoxuf4ilva0tw-cyl00cwc71rp0jfp59eyfhp4x 192.168.2.81:2377
常用命令
命令 | 说明 |
---|---|
docker swarm init | 初始化集群 |
docker swarm join-token worker | 查看工作节点的 token |
docker swarm join-token manager | 查看管理节点的 token |
docker swarm join | 加入集群 |
查看节点信息
docker info
![image-20220704145815755](https://i-blog.csdnimg.cn/blog_migrate/e278645ace558e5d8c29c9a836a013d3.png)
查看节点列表
docker node ls
节点 ID 旁边的*
表示当前已在此节点上连接
[root@manager ~]# docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
44qw5hbq836fryftoc51pnlbn * manager Ready Active Leader 20.10.17
q3yd5vno8t4c9hgi47mqztzbr node1 Ready Active 20.10.17
svwqj9t6g4izhsbnh0oneq4lw node2 Ready Active 20.10.17
注意,manager
是管理集群的入口,docke
r命令都是在manager
上执行,node
节点上是不能执行docker
命令的
[root@node1 ~]# docker node ls
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.
查看节点详细信息
使用以下命令查看节点的详情:
docker node inspect --pretty 节点名称
添加新的 Manager Node 到集群
在另一台机器运行 docker swarm join
命令加入已存在的集群中
docker swarm join --token SWMTKN-1-5d47eim8blk5jh37ww2eua7ve0r3u4w106j7oaoxuf4ilva0tw-cyl00cwc71rp0jfp59eyfhp4x 192.168.2.81:2377
Manager Node 必须是单数(Raft),生产环境推荐3台或5台作为 Manager Node
docker swarm join-token manager
命令用于获取添加新的 Manager Node 的命令参数
添加新的 Worker Node 到集群
在另一台机器运行
docker swarm join
命令加入已存在的集群中
docker swarm join --token SWMTKN-1-5qv7t73fvawvh795ckh3nxl9vnyo2hwwsqnnjwqyav3spj7ufu-1i7wir7oc3g9fh7yidg19i8p5 192.168.1.80:2377
docker swarm join-token worker
命令用于获取添加新的 Worker Node 的命令参数
禁用节点
在生产环境 Manager Node 不推荐运行任何容器实例,但是 Swarm 调度器会分配给Manager Node,
可以通过 禁用节点 告诉 Swarm 调度器不要分配给 Manager Node 任何容器实例。
docker node update --availability drain 节点名称
启用节点
禁用节点后使用以下命令即可启用节点
docker node update --availability active 节点名称
更新节点
docker node update --label-add foo --label-add bar=baz 节点名称
–label-add:给节点添加标签,可以用来控制服务放置
常用命令
命令 | 说明 |
---|---|
docker node ls | 查看所有集群节点 |
docker node rm | 删除某个节点(-f 强制删除) |
docker node inspect | 查看节点详情 |
docker node demote | 节点降级,由管理节点降级为工作节点 |
docker node promote | 节点升级,由工作节点升级为管理节点 |
docker node update | 节点升级,由工作节点升级为管理节点 |
docker node ps | 查看节点中的 Task 任务 |
服务管理
参考文档:将服务部署到群|Docker 文档
将服务部署到 swarm 时,swarm 管理器接收服务定义作为服务的所需状态。然后,它将群中的节点上的服务调度为一个或多个副本任务。这些任务在群中的节点上彼此独立运行。
例如,假设在 HTTP 侦听器的三个实例之间进行负载平衡。下图显示了具有三个副本的 HTTP 侦听器服务。侦听器的三个实例中的每一个都是群中的一个任务。
运行服务
连接到 Manager Node,使用
docker service create
命令创建服务.
例:
docker service create --replicas 1 --name helloworld alpine ping docker.com
-
--name
指定服务名称为helloworld
-
--replicas
指定服务运行实例数量为1
-
参数
alpine
表示运行的镜像为Alpine Linux
-
参数
ping docker.com
表示在容器中执行的命令
查看运行的服务
在 Manager Node 运行此命令查看正在运行的服务列表:
docker service ls
例:
[root@manager ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
82bpay4gdvd0 deploy-demo_nginx replicated 3/3 nginx:latest *:8088->80/tcp
7cad5hto20ql deploy-demo_portainer replicated 1/1 portainer/portainer:latest *:9000->9000/tcp
520x2l3lcwyp redis replicated 2/2 redis:3.0.6 *:6379->6379/tcp
查看服务的详细信息
在 Manager Node 运行此命令查看服务的运行详情:
docker service inspect --pretty 服务名称
参数
--pretty
表示返回格式化后的详细信息,不加这个参数则打印JSON
格式的信息
查看服务运行在哪些节点
在 Manager Node 使用此命令查看服务都在那些节点运行:
docker service ps 服务名称
docker-swarm 中的服务实例由 swarm 调度。因此有部分服务的实例运行在 Manager Node 是正常表现。
伸缩服务
docker-swarm 支持对服务实例进行动态伸缩,使用以下命令即可实现:
docker service scale 服务名称=实例数量(最少为1)
例:
[root@manager ~]# docker service scale redis=2
redis scaled to 2
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
删除服务
在 Manager Node 使用以下命令删除服务:
docker service rm 服务名称
注意,因为是集群的原因,集群中的Node将会存在延迟的情况,想确认服务是否被删除成功请使用
docker service ls
查看
滚动更新服务
创建服务
进入 Manager Node 创建一个redis服务用于演示滚动更新:
docker service create \
--replicas 3 \
--name redis \
--update-delay 10s \
redis:3.0.6
--update-dely
表示更新服务或服务集之间的时间延迟:1h10m3s
,表示延迟1小时10分钟3秒。
调度器默认一次更新一个任务,可以通过
--update-parallelism
参数配置调度器同时更新服务数量。
默认情况下,当单个服务更新返回状态为
RUNNING
,调度器会让另一个服务更新,直到所有服务都更新完成。
如果在更新期间某个服务返回
FAILED
,调度器会暂停更新,可以通过--update-failure-action
参数配置控制当服务更新发生错误时的行为。
检查服务状态
docker service inspect --pretty redis
更新服务
docker service update --image redis:3.0.7 redis
默认情况下,调度器将按以下方式更新服务:
-
停止一个服务
-
更新已停止的服务
-
启动已更新的服务
如果更新的服务返回
RUNNING
,等待指定的延迟时间后开始更新下一个服务
如果更新期间某个服务返回
FAILED
,则暂停服务更新
重新启动暂停的服务更新
docker service update redis
为了避免重复某些失败的更新,可以重新指定更新参数
查看服务的滚动更新
docker service ps redis
在swarm更新完成所有服务之前,可以看到一些服务的镜像为
redis:3.0.6
,另一些为redis:3.0.7
指定服务约束
常用命令
命令 | 说明 |
---|---|
docker service create | 部署服务 |
docker service inspect | 查看服务详情 |
docker service logs | 查看某个服务日志 |
docker service ls | 查看所有服务详情 |
docker service rm | 删除某个服务(-f 强制删除) |
docker service scale | 设置某个服务个数 |
docker service update | 更新某个服务 |
路由网格
docker swarm支持路由网格。路由网格让处于swarm集群中的任意一个节点都可以作为被访问的入口,即使此节点没有运行任何服务。
要在 swarm 集群中使用使用路由网格,首先需要开启加入swarm集群的节点的以下端口:
-
7946
:容器网络发现 -
4789
:容器网络入口
其次需要将节点服务实例的端口公开,使服务可以被外部访问(例如使用nginx做负载均衡)
服务原理
创建服务时公开端口
docker service create \
--name <SERVICE-NAME> \
--publish published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<IMAGE>
--publish
与-p
效果相同,其中--published
值为公布的端口,target
值为容器内部监听的端口。--publish
的写法
更新现有服务的公开端口
docker service update \
--publish-add published=<PUBLISHED-PORT>,target=<CONTAINER-PORT> \
<SERVICE>
查看服务发布的端口
docker service inspect --format="{{json .Endpoint.Spec.Ports}}" 服务名称
只公开TCP或UDP端口
默认情况下公开端口都是 TCP 端口,你可以通过参数配置公开端口的类型:
仅TCP
docker service create --name dns-cache \
--publish published=53,target=53 \
dns-cache
或
docker service create --name dns-cache \
-p 53:53 \
dns-cache
仅UDP
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp \
dns-cache
或
docker service create --name dns-cache \
-p 53:53/udp \
dns-cache
TCP+UDP
docker service create --name dns-cache \
--publish published=53,target=53 \
--publish published=53,target=53,protocol=udp \
dns-cache
或
docker service create --name dns-cache \
-p 53:53 \
-p 53:53/udp \
dns-cache
绕过路由网格
要绕过 swarm 集群的路由网格,需要使用
--publish
参数设置 mode
值为host
。
下面的命令使用
host
模式创建全局服务并绕过路由网格:
docker service create --name dns-cache \
--publish published=53,target=53,protocol=udp,mode=host \
--mode global \
dns-cache
绕过路由网格后的注意事项:
如果你访问未运行服务的节点,则无法访问此服务
如果你希望在每个节点运行多个服务,就不能指定静态的端口。要么就允许docker随机分配一个公开端口(通过置空
published
参数的值实现)
Stack-Deploy
正式部署集群服务,使用nginx
镜像做为示例
[root@manager ~]# docker service create --replicas 3 -p 8088:80 --name nginx nginx:latest
ap8h8srb8yh3mni0h2nz61njz
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
--replicas 3
表示创建服务的实例个数(默认1个),在个Docker节点上,分别创建一个nginx
服务,REPLICAS
会有进度显示,并且执行是异步的
查看服务
[root@manager ~]# docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
82bpay4gdvd0 deploy-demo_nginx replicated 3/3 nginx:latest *:8088->80/tcp
520x2l3lcwyp redis replicated 2/2 redis:3.0.6 *:6379->6379/tcp
访问任一节点8088端口:
docker service
部署的是单体服务,我使用docker stack
进行多服务编排部署,使用的同样是docker-compose.yml
配置文件,示例:
version: "3"
services:
nginx:
image: nginx:latest
ports:
- 8088:80
deploy:
mode: replicated
replicas: 3
portainer:
image: portainer/portainer:latest
ports:
- "9000:9000"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
deploy:
replicas: 1
placement:
constraints: [node.role == manager] ## 约束服务 仅在manager node 分配
部署命令:
[root@manager ~]# docker stack deploy -c docker-compose.yml deploy-demo
Creating service deploy-demo_nginx
Creating service deploy-demo_portainer
查看部署详情:
[root@manager ~]# docker stack ls
NAME SERVICES ORCHESTRATOR
deploy-demo 2 Swarm
访问portainer
,可以方便的查看和管理所有的服务和堆栈
编写支持docker stack
的docker-compose.yml
示例:
version: "3.9"
services:
db:
image: redis:3.0.5
deploy:
replicas: 6 # 启动实例数量
placement: # 配置容器实例位置------------
max_replicas_per_node: 2 # 每个节点最多运行容器实例数量
constraints: # 将容器分配到匹配标签的节点运行
- "node.role==manager"
- "engine.labels.operatingsystem==ubuntu 18.04"
preferences: # 将任务平均分配到不同类别的节点上
- spread: node.labels.zone
resources: # 资源限制------------
limits: # 占用上限
cpus: '0.50'
memory: 50M
reservations: # 启动占用
cpus: '0.25'
memory: 20M
restart_policy: # 重启策略------------
condition: on-failure # 发生失败时
delay: 5s # 重启时间间隔
max_attempts: 3 #最大尝试次数
window: 120s # 判断是否重启成功的等待时长
update_config: # 滚动更新的配置------------
parallelism: 2 # 同时更新的数量
delay: 10s # 每次更新间隔时间
monitor: 5s # 每次更新监控失败持续的时长
failure_action: 'pause' # 滚动更新出现错误时执行的操作: continue/rollback/pause
max_failure_ratio: # 允许的更新失败率
order: stop-first # 更新顺序 stop-first(旧任务在启动新任务之前停止)或start-first(新任务首先启动,运行中的任务会出现短暂重叠)
rollback_config: # 更新失败如何回滚------------
parallelism: 2 # 每次回滚的数量,如果为0则全部回滚
delay: 10s # 每次回滚间隔时间
monitor: 5s # 每次更新监控失败持续的时长
failure_action: 'pause' # 回滚出现错误时执行的操作: continue/rollback/pause
max_failure_ratio: # 允许的回滚失败率,默认为0
order: stop-first # 回滚顺序 stop-first(旧任务在启动新任务之前停止)或start-first(新任务首先启动,运行中的任务会出现短暂重叠)
docker-stack
不支持的docker-compose
配置
常用命令
命令 | 说明 |
---|---|
docker stack deploy | 部署新的堆栈或更新现有堆栈 |
docker stack ls | 列出现有堆栈 |
docker stack ps | 列出堆栈中的任务 |
docker stack rm | 删除堆栈 |
docker stack services | 列出堆栈中的服务 |
docker stack down | 移除某个堆栈(不会删除数据) |
其他文档
配置管理
普通配置
加密配置
锁定集群
管理指南
遇到的坑
问题描述
使用swarm搭建集群时出现如下错误:
Error response from daemon: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: Error while dialing dial tcp 192.168.0.108:2377: connect: no route to host"
这个错误是因为将node节点加入swarm中导致的,原因就是manager
节点这台机器上的防火墙没有关闭。
问题解决
把manager这台机器上的防火墙关闭
## 查看防火墙状态
systemctl status firewalld.service
## 停止防火墙
systemctl stop firewalld.service
## 禁用防火墙
systemctl disable firewalld.service
Docker Swarm 错误 :
error creating external connectivity network: Failed to Setup IP tables: Unable to enable SKIP DNAT rule: (iptables failed: iptables --wait -t nat -I DOCKER -i docker_gwbridge -j RETURN: iptables: No chain/target/match by that name. (exit status 1))
关闭防火墙后需要重启Docker
service docker restart
systemctl restart docker