我们的系统属于中小规模,一直没有上 k8s,觉得有点大材小用。从年初我将所有服务迁移到 Docker Swarm 以来,服务一直运行很稳定,还没有出现因架构导致的重大问题,所以写篇文章记录一下。
什么是 Docker Swarm
Docker Swarm 是内置在 Docker
中的容器集群编排工具,它为 Docker
补足了服务治理方面的能力,提供了路由网格、服务发现、负载均衡、动态伸缩、滚动更新等功能。
简单来说,如果你有很少几个服务运行,那么使用 Docker
容器管理应用即可。当你的服务越来越多时,就会需要一个工具来管理所有的容器,而 Docker Swarm
就是 Docker
内建的一种解决方案。
在 Kubernetes
已经成为事实上业界标准的今天,Docker Swarm
无论功能还是社区活跃度都无法与之匹敌,但它仍在市场上占有一席之地。根据 RightScale
最新的市场统计结果(State of Cloud Report 2023),Docker Swarm
是除了 k8s(商业或自建)以外使用率最高的容器管理平台。
Docker Swarm
相对其他容器编排工具来说有以下几个特点
原生支持
Docker Swarm 因为内置在 Docker 中,是可以开箱即用的,安装好了 Docker 就可以立即启动 Swarm 了。
配置简单
Docker Swarm 可以通过 docker-compose.yaml
清单文件管理服务,如果你之前使用过 docker compose
,那么只需要添加几行配置就可以把服务部署到 Swarm 中。
学习曲线平滑
因为 Docker Swarm 并没有跳脱出 Docker 这个框架,所以相比于学习 Kubernetes 中的一大堆专有名词和“新概念”,Docker Swarm 的学习难度是非常低的。
兼容 Standalone 容器
部署在 Docker Swarm 中的服务可以很好的和直接运行在 Docker 上的独立容器共存,所以只将一部分容器服务部署到 Swarm 中也是可以的。
快速部署
初始化集群
Docker Swarm
集群中的主机称为节点 Node
,他们有两种角色 Manager
管理节点和 Worker
工作节点,管理节点负责将工作负载分发到工作节点上,并且一个集群中可以有多个 Manager 和多个 Worker,它们的关系如下图
使用下面的命令初始化一个 Manager
节点
执行成功后会看到这样一段输出:
把它提示的这行命令在同一个局域网下的其他主机上运行,即可作为 Worker
节点加入到集群中
使用 node ls
命令可以查看集群中节点概况
部署服务
使用 docker service
命令可以管理 Swarm 服务,在管理节点上执行下面的命令启动一个 Nginx
服务
这样我们就创建了一个具有 3 个实例(有 3 个容器运行)的 nginx 服务,并且开放了容器的 80 端口到所有节点的 8080
端口上,此时我们访问任何一个节点的 8080 端口,都可以访问到 nginx 服务。
使用 service ls
命令查看服务的概况
使用 service ps
命令查看服务的具体状态
可以看到这个服务有 3 个实例,在 Swarm 中这些实例叫做 Task
任务,管理节点会将任务分配到不同的节点上执行,上面的 NODE
列显示的就是任务由哪个节点负责。
服务发现
当我们访问节点的 8080 端口时,我们实际上连接到了三个实例的其中一个,Swarm 帮我们将请求路由到负载较小的实例上。
具体来说,Swarm 默认的服务发现是通过 vip
(虚拟 IP)实现的,它根据节点上的连接数量判断节点负载来实现负载均衡,这使客户端的多次请求可能会被不同的实例接收。关于 Swarm 服务发现的更多细节可以在这里找到。
服务日志
使用 service logs
命令可以查看服务的日志。服务上多个实例的日志会合并到一起。
服务堆
只部署一两个服务时使用 docker service
命令很方便,一旦系统中的服务越来越多,我们就需要一个工具来管理服务了。
docker stack
就是 Swarm 用来批量管理服务的工具,docker stack
之于 service 正如 docker compose
之于 container。
使用 compose 文件管理服务
通过命令管理服务的方式不仅效率低,也不利于批量管理。docker stack
采用 compose
文件管理集群配置,例如下面的文件定义了 nginx 服务的各项细节
在这个文件所在目录下,执行下面的命令就可以启动这个 stack
使用 stack ls
命令查看 stack 的概况
使用 stack ps
命令查看这个 stack 的详细信息
一个 compose
文件中可以定义多个服务,例如下面这个 WordPress
服务
这个文件定义了一个具有 3 个实例的 wordpress 服务和一个全局唯一实例的 mysql 服务。它们共同加入 overlay
这个网络,所以 wordpress 服务可以通过 db:3306
地址访问到数据库。
服务升级
通过命令升级
对于使用 service create
创建的服务,我们可以通过 service update
命令升级
--image
参数指定了服务升级的镜像,还可以通过 --env-add
--publish-add
等参数来更新环境变量、端口等。
其他参数的详细用法可以通过 docker service update -h
查看。
升级 stack 中的服务
修改 compose
文件中的 image
字段,然后重新执行 docker stack deploy
命令即可。
滚动升级
通过指定 compose
文件中的 deploy.update_config
配置,可以控制滚动更新的行为
配置的详细说明
parallelism
: 每次更新的容器数量
delay
: 每组容器更新后的等待时长
failure_action
: 更新失败后的操作,可选值有 continue(继续更新)rollback(回滚)pause(暂停更新),默认为 pause
monitor
: 更新后检查是否失败的时长(默认为 0)
max_failure_ratio
: 更新期间可容忍的故障率
order
: 操作的执行顺序,可选值有 stop-first(先停止旧实例再启动新实例) start-first(先启动新实例再停止旧实例,运行中的任务会短暂重叠)(默认为 stop-first)
服务回滚
使用 stack 管理服务时一般不需要手动回滚,因为滚动更新配置的 failure_action
可以自动回滚有问题的服务。
也可以使用 service rollback
命令手动回滚服务
回滚时的具体行为可以通过 compose
文件的 deploy.rollback_config
配置
回滚配置和 update_config
相同,只有 failure_action
字段不可以指定为 rollback
。
服务扩缩容
使用 stack 管理服务时,直接修改 compose
文件的 replicas
数量然后执行 docker stack deploy
即可扩缩容。
使用 service create
创建的服务可以通过 service scale
对服务进行扩缩容