Docker 三剑客之 Docker Swarm
Docker Swarm是管理跨节点容器的编排工具,相较于Docker Compose而言,Compose只能编排单节点上的容器,Swarm将一群Docker节点虚拟化为一个主机,使得用户只要在单一主机上操作就能完成对整个容器集群的管理工作。
准备工作
准备三个节点,要求实现奇数个节点
1 | 192.168.2.1 ————作为manager |
三个节点在同一个网段,确保相互之间可以ping通
安装Docker-Engine
查看是否安装成功
1 | [root@manager ~]# docker --version |
节点管理
如下图所示,swarm 集群由管理节点(manager)和工作节点(work node)构成。
- swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
- work node:即图中的 available node,主要负责运行相应的服务来执行任务(task)
在创建集群之前,使用docker node ls
想查看下集群中节点的信息,反馈目前没有节点信息,并且当前节点并不是manager
1 | [root@manager ~]# docker node ls |
创建一个Swarm
在创建集群之前,使用docker node ls
想查看下集群中节点的信息,反馈目前没有节点信息,并且当前节点并不是manager
1 | [root@manager ~]# docker node ls |
创建新的集群
1 | docker swarm init --advertise-addr 192.168.2.1 |
示例:
1 | [root@manager ~]# docker swarm init --advertise-addr 192.168.2.81 |
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
上执行第一个命令即可:
1 | docker swarm join --token SWMTKN-1-xxxxxxxx-cyl00cwc71rp0jfp59eyfhp4x 192.168.2.81:2377 |
常用命令
命令 | 说明 |
---|---|
docker swarm init | 初始化集群 |
docker swarm join-token worker | 查看工作节点的 token |
docker swarm join-token manager | 查看管理节点的 token |
docker swarm join | 加入集群 |
查看节点信息
1 | docker info |
查看节点列表
1 | docker node ls |
节点 ID 旁边的*
表示当前已在此节点上连接
1 | [root@manager ~]# docker node ls |
注意,manager
是管理集群的入口,docke
r命令都是在manager
上执行,node
节点上是不能执行docker
命令的
1 | [root@node1 ~]# docker node ls |
查看节点详细信息
使用以下命令查看节点的详情:
1 | docker node inspect --pretty 节点名称 |
添加新的 Manager Node 到集群
在另一台机器运行 docker swarm join
命令加入已存在的集群中
1 | 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
命令加入已存在的集群中
1 | 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 任何容器实例。
1 | docker node update --availability drain 节点名称 |
启用节点
禁用节点后使用以下命令即可启用节点
1 | docker node update --availability active 节点名称 |
更新节点
1 | 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
命令创建服务.
例:
1 | docker service create --replicas 1 --name helloworld alpine ping docker.com |
--name
指定服务名称为helloworld
--replicas
指定服务运行实例数量为1
参数
alpine
表示运行的镜像为Alpine Linux
参数
ping docker.com
表示在容器中执行的命令
查看运行的服务
在 Manager Node 运行此命令查看正在运行的服务列表:
1 | docker service ls |
例:
1 | [root@manager ~]# docker service ls |
查看服务的详细信息
在 Manager Node 运行此命令查看服务的运行详情:
1 | docker service inspect --pretty 服务名称 |
参数
--pretty
表示返回格式化后的详细信息,不加这个参数则打印JSON
格式的信息
查看服务运行在哪些节点
在 Manager Node 使用此命令查看服务都在那些节点运行:
1 | docker service ps 服务名称 |
docker-swarm 中的服务实例由 swarm 调度。因此有部分服务的实例运行在 Manager Node 是正常表现。
伸缩服务
docker-swarm 支持对服务实例进行动态伸缩,使用以下命令即可实现:
1 | docker service scale 服务名称=实例数量(最少为1) |
例:
1 | [root@manager ~]# docker service scale redis=2 |
删除服务
在 Manager Node 使用以下命令删除服务:
1 | docker service rm 服务名称 |
注意,因为是集群的原因,集群中的Node将会存在延迟的情况,想确认服务是否被删除成功请使用
docker service ls
查看
滚动更新服务
创建服务
进入 Manager Node 创建一个redis服务用于演示滚动更新:
1 | docker service create \ |
--update-dely
表示更新服务或服务集之间的时间延迟:1h10m3s
,表示延迟1小时10分钟3秒。
调度器默认一次更新一个任务,可以通过
--update-parallelism
参数配置调度器同时更新服务数量。
默认情况下,当单个服务更新返回状态为
RUNNING
,调度器会让另一个服务更新,直到所有服务都更新完成。
如果在更新期间某个服务返回
FAILED
,调度器会暂停更新,可以通过--update-failure-action
参数配置控制当服务更新发生错误时的行为。
检查服务状态
1 | docker service inspect --pretty redis |
更新服务
1 | docker service update --image redis:3.0.7 redis |
默认情况下,调度器将按以下方式更新服务:
停止一个服务
更新已停止的服务
启动已更新的服务
如果更新的服务返回
RUNNING
,等待指定的延迟时间后开始更新下一个服务
如果更新期间某个服务返回
FAILED
,则暂停服务更新
重新启动暂停的服务更新
1 | docker service update redis |
为了避免重复某些失败的更新,可以重新指定更新参数
查看服务的滚动更新
1 | 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做负载均衡)
服务原理
创建服务时公开端口
1 | docker service create \ |
--publish
与-p
效果相同,其中--published
值为公布的端口,target
值为容器内部监听的端口。--publish
的写法
更新现有服务的公开端口
1 | docker service update \ |
查看服务发布的端口
1 | docker service inspect --format="{{json .Endpoint.Spec.Ports}}" 服务名称 |
只公开TCP或UDP端口
默认情况下公开端口都是 TCP 端口,你可以通过参数配置公开端口的类型:
仅TCP
1 | docker service create --name dns-cache \ |
或
1 | docker service create --name dns-cache \ |
仅UDP
1 | docker service create --name dns-cache \ |
或
1 | docker service create --name dns-cache \ |
TCP+UDP
1 | docker service create --name dns-cache \ |
或
1 | docker service create --name dns-cache \ |
绕过路由网格
要绕过 swarm 集群的路由网格,需要使用
--publish
参数设置 mode
值为host
。
下面的命令使用
host
模式创建全局服务并绕过路由网格:
1 | docker service create --name dns-cache \ |
绕过路由网格后的注意事项:
如果你访问未运行服务的节点,则无法访问此服务
如果你希望在每个节点运行多个服务,就不能指定静态的端口。要么就允许docker随机分配一个公开端口(通过置空
published
参数的值实现)
Stack-Deploy
正式部署集群服务,使用nginx
镜像做为示例
1 | [root@manager ~]# docker service create --replicas 3 -p 8088:80 --name nginx nginx:latest |
--replicas 3
表示创建服务的实例个数(默认1个),在个Docker节点上,分别创建一个nginx
服务,REPLICAS
会有进度显示,并且执行是异步的
查看服务
1 | [root@manager ~]# docker service ls |
访问任一节点8088端口:
docker service
部署的是单体服务,我使用docker stack
进行多服务编排部署,使用的同样是docker-compose.yml
配置文件,示例:
1 | version: "3" |
部署命令:
1 | [root@manager ~]# docker stack deploy -c docker-compose.yml deploy-demo |
查看部署详情:
1 | [root@manager ~]# docker stack ls |
访问portainer
,可以方便的查看和管理所有的服务和堆栈
编写支持docker stack
的docker-compose.yml
示例:
1 | version: "3.9" |
docker-stack
不支持的docker-compose
配置
常用命令
命令 | 说明 |
---|---|
docker stack deploy | 部署新的堆栈或更新现有堆栈 |
docker stack ls | 列出现有堆栈 |
docker stack ps | 列出堆栈中的任务 |
docker stack rm | 删除堆栈 |
docker stack services | 列出堆栈中的服务 |
docker stack down | 移除某个堆栈(不会删除数据) |
其他文档
配置管理
普通配置
加密配置
锁定集群
管理指南
遇到的坑
问题描述
使用swarm搭建集群时出现如下错误:
1 | 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这台机器上的防火墙关闭
1 | # 查看防火墙状态 |
Docker Swarm 错误 :
1 | 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
1 | service docker restart |