Docker Swarm 深度实践:从集群搭建、服务编排到生产级运维
欢迎你来读这篇博客。
前面几篇文章分别讲了 Docker 基础、Docker Compose、Dockerfile、Docker Tools。这一篇专门讲 Docker Swarm,也就是 Docker
原生的集群编排能力。
本文核心内容包括:
- Docker Swarm 是什么
- Docker Swarm 和 Docker Compose、Kubernetes 的区别
- Swarm 集群架构
- Manager、Worker、Raft、Quorum
- Service、Task、Container 的关系
- 集群端口、防火墙和节点规划
- 搭建 Docker Swarm 集群
- 服务部署、扩缩容、滚动更新、回滚
- Overlay 网络、Ingress 网络和 Routing Mesh
- 服务发现、VIP、DNSRR
- Secret、Config
- Stack 部署
- 数据卷和有状态服务的坑
- 节点维护、Drain、Label、Placement
- 高可用、备份、恢复、故障排查
- 生产实践和常用脚本
Docker Swarm 的定位可以用一句话概括:
用 Docker 原生命令,把多台 Docker 主机变成一个可以调度服务的集群。
如果 Docker Compose 是“单机多容器编排”,那么 Docker Swarm 就是“多机服务编排”。
它没有 Kubernetes 那么庞大,也没有 Kubernetes 那么复杂。优点是简单、内置、Docker 原生;缺点是生态和扩展能力没有 Kubernetes 强。
Swarm 就像一把短刀:不花哨,但拔出来就能用。
Kubernetes 更像一套军械库:功能强,但你得先学会别把自己炸了。
一、Docker Swarm 是什么?
Docker Swarm 是 Docker Engine 内置的集群管理和服务编排能力。
它可以把多台安装了 Docker Engine 的机器组成一个集群,然后在集群上运行服务。
Docker Swarm 能做这些事情:
- 创建多节点 Docker 集群
- 管理 manager 和 worker 节点
- 部署服务
- 扩缩容服务副本
- 服务发现
- 负载均衡
- 滚动更新
- 服务回滚
- 节点故障迁移
- Overlay 跨主机网络
- Secret 和 Config 管理
- Stack 应用部署
- 基于约束的服务调度
1. Docker Swarm 的基本结构
flowchart TB
subgraph SwarmCluster[Docker Swarm Cluster]
subgraph Managers[Manager Nodes]
M1[manager-1 Leader]
M2[manager-2 Reachable]
M3[manager-3 Reachable]
end
subgraph Workers[Worker Nodes]
W1[worker-1]
W2[worker-2]
W3[worker-3]
end
M1 <-->|Raft| M2
M2 <-->|Raft| M3
M1 <-->|Raft| M3
M1 -->|Schedule Tasks| W1
M1 -->|Schedule Tasks| W2
M1 -->|Schedule Tasks| W3
end
USER[Docker CLI / API] --> M1
2. Swarm mode 不是 Classic Swarm
这里要特别说明:
- Swarm mode 是 Docker Engine 内置的现代 Swarm 能力。
- Classic Swarm 是早期项目,已经不是现在主流讨论的对象。
我们平时说 Docker Swarm,一般默认指 Docker Engine 的 Swarm mode。
3. Docker Swarm 适合什么场景?
适合:
- 中小规模服务部署
- 内部系统
- 自托管服务集群
- 简单微服务集群
- 边缘节点集群
- 已经熟悉 Docker CLI 的团队
- 不想引入 Kubernetes 复杂度的场景
- 需要比 Compose 更强的多机编排能力
不太适合:
- 大规模云原生平台
- 极复杂服务治理
- 复杂 Operator 生态
- 强依赖 Kubernetes 生态的公司
- 多租户、强隔离、复杂权限场景
- 超大规模弹性调度
可以这样理解:
| 工具 | 定位 |
|---|---|
| Docker CLI | 单容器操作 |
| Docker Compose | 单机多容器编排 |
| Docker Swarm | 多机 Docker 原生编排 |
| Kubernetes | 大规模云原生编排平台 |
二、Docker Swarm 核心概念
学习 Swarm 先不要急着敲命令。
先把几个对象之间的关系搞清楚,不然后面看到 Service、Task、Container 很容易乱。
1. Swarm
Swarm 是一个 Docker Engine 集群。
一个 Swarm 由多个 Node 组成,每个 Node 本质上都是一台运行 Docker Engine 的机器。
2. Node
Node 是 Swarm 集群中的一台主机,可以是物理机,也可以是虚拟机。
Node 分为两类:
- Manager Node
- Worker Node
3. Manager Node
Manager 节点负责集群管理。
职责包括:
- 维护集群状态
- 调度 Service
- 分配 Task
- 管理节点加入和退出
- 保存 Raft 状态
- 处理 Docker Swarm API 请求
- 管理 Secret 和 Config
- 参与 Leader 选举
Manager 节点也可以运行容器任务。
但生产环境通常建议把 Manager 设置为 Drain,让它只做管理,不跑业务。
4. Worker Node
Worker 节点负责执行任务。
它不参与 Raft,不做调度决策,也不维护全局集群状态。
它接收 Manager 分配的 Task,然后运行对应容器。
5. Service
Service 是 Swarm 里最核心的部署对象。
它描述的是“期望状态”,例如:
- 用哪个镜像
- 运行几个副本
- 暴露哪个端口
- 挂载哪些卷
- 使用哪些网络
- 使用哪些 Secret
- 部署到哪些节点
- 如何滚动更新
- 失败后如何重启
例如:
1 | |
这表示:
我希望集群里运行一个名为 web 的服务,副本数为 3,对外发布 8080 端口,容器里监听 80 端口,镜像是 nginx。
6. Task
Task 是 Service 的一次具体调度执行。
一个 Service 有多个副本,每个副本对应一个 Task。
Task 再对应一个实际运行的 Container。
关系如下:
flowchart LR
S[Service: web replicas=3] --> T1[Task web.1]
S --> T2[Task web.2]
S --> T3[Task web.3]
T1 --> C1[Container on worker-1]
T2 --> C2[Container on worker-2]
T3 --> C3[Container on worker-3]
7. Container
Container 是最终运行的容器实例。
在 Swarm 中,不建议直接用 docker run 管理业务容器。
应该用 docker service create 或 docker stack deploy。
因为:
docker run是单机行为docker service是集群行为- Swarm 只会维护 Service 的期望状态,不会维护你手工
docker run的容器
8. Desired State 期望状态
Swarm 的核心思想是 Desired State。
你告诉 Swarm:
1 | |
Swarm 会尽力让真实状态保持为:
1 | |
如果某个 worker 挂了,上面的 task 消失,Manager 会把 task 重新调度到其他可用节点。
这就是编排系统和普通容器启动命令最大的区别。
三、Docker Swarm 工作机制
1. 服务创建流程
sequenceDiagram
participant User as 用户 / Docker CLI
participant Manager as Manager Leader
participant Raft as Raft 状态存储
participant Scheduler as Scheduler
participant Worker1 as Worker 1
participant Worker2 as Worker 2
User ->> Manager: docker service create
Manager ->> Raft: 写入 Service 期望状态
Manager ->> Scheduler: 根据副本数和约束调度 Task
Scheduler ->> Worker1: 分配 Task web.1
Scheduler ->> Worker2: 分配 Task web.2
Worker1 ->> Worker1: 拉取镜像并启动容器
Worker2 ->> Worker2: 拉取镜像并启动容器
Worker1 -->> Manager: 上报 Task 状态
Worker2 -->> Manager: 上报 Task 状态
2. 节点故障流程
假设 worker-1 挂了:
flowchart TB
A[worker-1 故障] --> B[Manager 检测节点不可用]
B --> C[worker-1 上的 Task 变为失败/不可达]
C --> D[Manager 根据 Service 期望状态重新调度]
D --> E[在 worker-2 或 worker-3 创建新 Task]
E --> F[副本数恢复到期望状态]
这个过程体现了 Swarm 的编排能力。
四、Raft、Quorum 和 Manager 高可用
Swarm Manager 通过 Raft 维护一致的集群状态。
这部分非常重要。很多 Swarm 集群出问题,不是容器问题,而是 Manager 规划错了。
1. 为什么需要 Raft?
Swarm 集群的状态包括:
- 有哪些节点
- 有哪些服务
- 服务副本数是多少
- Task 分配到哪里
- 网络、Secret、Config 等对象
- 当前哪个节点是 Leader
这些状态必须在多个 Manager 中保持一致。
Raft 就是用来让多个 Manager 对集群状态达成一致。
2. Leader 和 Reachable
Manager 节点常见状态:
| 状态 | 含义 |
|---|---|
| Leader | 当前主 Manager,负责调度和写入决策 |
| Reachable | 可达 Manager,参与 Raft,同步状态 |
| Unreachable | 不可达 Manager,需要排查 |
| Down | 节点不可用 |
查看:
1 | |
示例:
1 | |
3. Quorum 多数派
Raft 需要多数 Manager 可用才能处理管理操作。
如果 Manager 数量是 N,那么需要超过一半可用。
| Manager 数量 | 多数派 Quorum | 可容忍 Manager 故障数 |
|---|---|---|
| 1 | 1 | 0 |
| 2 | 2 | 0 |
| 3 | 2 | 1 |
| 4 | 3 | 1 |
| 5 | 3 | 2 |
| 6 | 4 | 2 |
| 7 | 4 | 3 |
所以生产环境建议:
- 1 个 Manager:只适合测试或极小环境
- 3 个 Manager:常见生产起步
- 5 个 Manager:更高可用
- 7 个 Manager:官方建议的较高上限
- 不建议 2、4、6 这种偶数 Manager,因为不会提升对应容错能力
4. 为什么不是 Manager 越多越好?
Manager 越多,需要达成一致的节点越多,写入性能反而会下降。
比如:
- 创建服务
- 更新服务
- 节点加入
- 节点删除
- Secret 更新
这些都涉及 Raft 状态变更,需要 Manager 多数派确认。
所以 Manager 不是越多越强。
多了以后不是“高可用”,是“高沟通成本”。
5. Manager 是否应该跑业务?
默认情况下,Manager 也可以跑业务 Task。
小集群可以这样做,但生产建议 Manager 专职管理。
设置 Manager 不接收业务任务:
1 | |
恢复可调度:
1 | |
五、Docker Swarm 网络端口规划
搭 Swarm 之前,必须先规划网络和防火墙。
1. Swarm 常用端口
| 端口 | 协议 | 用途 | 是否必须 |
|---|---|---|---|
| 2377 | TCP | 集群管理通信,节点加入 Manager | Manager 需要 |
| 7946 | TCP/UDP | 节点间通信、服务发现、Gossip | 所有节点需要 |
| 4789 | UDP | Overlay 网络 VXLAN 数据面 | 所有节点需要 |
| 发布端口 | TCP/UDP | 业务服务对外端口 | 按业务需要 |
2. 防火墙示例
假设集群内网网段:
1 | |
UFW 示例:
1 | |
如果业务端口只给负载均衡器访问:
1 | |
3. Manager 建议使用固定 IP
Manager 节点用于维护集群状态和节点通信,建议使用固定 IP。
初始化时:
1 | |
如果 Manager IP 经常变化,其他节点可能找不到它,集群稳定性会受影响。
Worker 可以使用动态 IP,但生产环境也建议尽量稳定。
六、搭建 Docker Swarm 集群
下面以 3 台机器为例:
| 主机名 | IP | 角色 |
|---|---|---|
| manager-1 | 10.0.0.11 | Manager |
| worker-1 | 10.0.0.21 | Worker |
| worker-2 | 10.0.0.22 | Worker |
所有机器都安装 Docker Engine。
1. 设置主机名
在 manager-1:
1 | |
在 worker-1:
1 | |
在 worker-2:
1 | |
可以配置 /etc/hosts:
1 | |
2. 初始化 Swarm
在 manager-1 执行:
1 | |
输出类似:
1 | |
3. Worker 加入集群
在 worker-1 和 worker-2 执行上面输出的 join 命令:
1 | |
如果忘了 join 命令,在 Manager 上查看:
1 | |
查看 Manager 加入命令:
1 | |
4. 查看节点
在 manager-1 执行:
1 | |
输出类似:
1 | |
5. 新增 Manager 节点
如果后续要把 worker-1 提升为 Manager:
1 | |
或者在新节点上使用 manager join token:
1 | |
6. 降级 Manager
1 | |
注意:不要把 Manager 降到没有 quorum。别在生产上练胆量,集群不是练习簿。
7. 节点退出 Swarm
Worker 主动退出:
1 | |
Manager 强制退出:
1 | |
从 Manager 删除节点:
1 | |
强制删除不可达节点:
1 | |
七、部署第一个 Swarm Service
1. 创建 Nginx 服务
在 Manager 上执行:
1 | |
含义:
| 参数 | 说明 |
|---|---|
--name web |
服务名 |
--replicas 3 |
运行 3 个副本 |
--publish published=8080,target=80 |
对外发布 8080,容器内 80 |
nginx:latest |
镜像 |
2. 查看服务
1 | |
查看具体 Task:
1 | |
输出类似:
1 | |
3. 访问服务
在任意节点访问:
1 | |
如果使用 ingress routing mesh,只要服务发布了端口,任意节点都可以接收该端口流量,并转发给实际运行 Task 的节点。
4. 查看服务详情
1 | |
5. 查看日志
1 | |
6. 删除服务
1 | |
八、服务扩缩容
1. 扩容
1 | |
查看:
1 | |
2. 缩容
1 | |
3. 多服务一起扩缩容
1 | |
4. 扩缩容背后的机制
flowchart LR
A[docker service scale web=5] --> B[Manager 更新期望状态 replicas=5]
B --> C[Scheduler 计算需要新增 Task]
C --> D[分配 Task 到合适节点]
D --> E[Worker 拉镜像并启动容器]
E --> F[服务副本数达到 5]
九、滚动更新与回滚
滚动更新是 Swarm 很实用的能力。
1. 创建带更新策略的服务
1 | |
参数说明:
| 参数 | 说明 |
|---|---|
--update-parallelism 1 |
每次更新 1 个 Task |
--update-delay 10s |
每批更新之间等待 10 秒 |
--update-failure-action rollback |
更新失败时自动回滚 |
--replicas 4 |
副本数为 4 |
2. 更新镜像
1 | |
查看更新过程:
1 | |
3. 更新环境变量
1 | |
删除环境变量:
1 | |
4. 更新资源限制
1 | |
5. 强制重启服务
有时候镜像 tag 没变,但想重启全部 Task:
1 | |
这也可以触发重新调度。
6. 回滚服务
1 | |
查看:
1 | |
7. 更精细的更新策略
1 | |
说明:
| 参数 | 说明 |
|---|---|
--update-parallelism |
同时更新几个 Task |
--update-delay |
每批更新时间间隔 |
--update-monitor |
更新后观察多久判断是否失败 |
--update-max-failure-ratio |
可接受失败比例 |
--update-failure-action |
失败后 pause / continue / rollback |
十、Routing Mesh:Swarm 的入口流量机制
Routing Mesh 是 Swarm 的核心特性之一。
当你发布一个服务端口时:
1 | |
Swarm 会让集群中所有节点都监听 8080。
即使某个节点没有运行 web 任务,访问这个节点的 8080 端口,也会被转发到真正运行 web task 的节点。
1. Routing Mesh 示意图
flowchart LR
Client[客户端] -->|访问 worker - 2:8080| W2[worker-2]
W2 -->|Routing Mesh| W1[worker-1]
W1 --> C1[web task container]
Client2[客户端] -->|访问 manager - 1:8080| M1[manager-1]
M1 -->|Routing Mesh| W3[worker-3]
W3 --> C2[web task container]
2. Routing Mesh 的优点
- 任意节点都可以作为入口
- 服务端口统一
- 不需要知道容器实际在哪个节点
- 外部负载均衡器可以把流量打到所有节点
- 服务副本迁移后入口不变
3. Routing Mesh 的缺点
- 多一层转发
- 排查链路更复杂
- 对某些需要源 IP 的场景不友好
- 高性能场景可能希望绕过它
- 需要所有节点开放发布端口
4. Ingress 模式发布端口
默认就是 ingress:
1 | |
5. Host 模式发布端口
绕过 routing mesh,直接在运行 Task 的节点上发布端口:
1 | |
注意:
如果 mode=host 且所有副本都要绑定同一个宿主机端口,那么同一个节点不能运行多个绑定同端口的 Task。
适合:
- 高性能入口
- 需要保留源 IP
- 配合外部负载均衡器
- 每个节点跑一个实例的 global 服务
十一、Overlay 网络
Docker 单机默认 bridge 网络只能在一台机器上工作。
Swarm 需要跨主机容器通信,所以使用 Overlay 网络。
1. 创建 Overlay 网络
1 | |
查看:
1 | |
2. 服务加入 Overlay 网络
1 | |
在同一个 Overlay 网络中,服务可以通过服务名访问:
1 | |
3. Overlay 网络通信图
flowchart TB
subgraph Node1[worker-1]
A[app task]
end
subgraph Node2[worker-2]
R[redis task]
end
A -->|redis:6379| R
subgraph Overlay[Overlay Network app-net]
A
R
end
4. 创建可被普通容器连接的 Overlay 网络
默认 overlay 网络用于 swarm service。
如果普通容器也要连接,需要 --attachable:
1 | |
然后普通容器可以:
1 | |
5. 加密 Overlay 网络
可以开启 overlay 网络加密:
1 | |
加密会增加 CPU 开销。
是否开启要看安全需求和性能要求。
6. Ingress 网络和自定义 Overlay 网络
| 网络 | 作用 |
|---|---|
| ingress | Swarm 内置,用于 routing mesh 和发布端口 |
| 自定义 overlay | 业务服务之间通信 |
| docker_gwbridge | 容器连接宿主机网络的桥接网络 |
业务服务之间建议使用自定义 overlay 网络,不要直接依赖默认 ingress 网络。
十二、服务发现和负载均衡
Swarm 内置 DNS 服务发现。
1. 通过服务名访问
创建网络:
1 | |
创建 Redis:
1 | |
创建应用:
1 | |
应用中可以配置:
1 | |
2. VIP 模式
默认 endpoint mode 是 VIP。
服务名会解析到一个虚拟 IP,Swarm 内部负载均衡再转发到具体 Task。
1 | |
创建 VIP 模式服务:
1 | |
3. DNSRR 模式
DNSRR 会让 DNS 查询返回多个 Task IP,由客户端自己负载均衡。
1 | |
适合:
- 客户端自己做负载均衡
- 某些服务发现框架
- 不想使用 VIP 负载均衡
注意:DNSRR 和 ingress 发布端口并不是所有组合都适合,需要根据实际服务设计。
十三、Secret:敏感配置管理
不要把密码写进镜像,也不要直接写在命令里。
错误示例:
1 | |
更推荐使用 Secret。
1. 创建 Secret
1 | |
查看:
1 | |
2. 服务使用 Secret
1 | |
Secret 默认挂载在:
1 | |
3. 在应用服务中读取 Secret
1 | |
容器内:
1 | |
应用可以读取该文件。
4. Secret 轮换
Swarm Secret 不支持直接修改内容。
通常做法是创建新版本:
1 | |
更新服务:
1 | |
确认服务正常后删除旧 Secret:
1 | |
5. Secret 使用建议
- Secret 用于密码、Token、私钥等敏感信息
- 不要把 Secret 写进镜像
- 不要把 Secret 放进 Git
- Secret 命名建议带版本
- 轮换时使用新 Secret 替换旧 Secret
- 服务不用的 Secret 要及时移除
十四、Config:非敏感配置管理
Config 类似 Secret,但用于非敏感配置。
适合:
- Nginx 配置
- 应用配置模板
- Prometheus 配置
- Fluent Bit 配置
- 静态配置文件
1. 创建 Config
1 | |
查看:
1 | |
2. 服务使用 Config
1 | |
3. Config 和 Secret 的区别
| 对比项 | Config | Secret |
|---|---|---|
| 用途 | 非敏感配置 | 敏感信息 |
| 是否加密存储 | 不按 Secret 语义处理 | 加密存储在 Raft 日志 |
| 默认挂载位置 | /<config_name> |
/run/secrets/<secret_name> |
| 示例 | nginx.conf | db_password |
4. Config 轮换
和 Secret 一样,不直接修改内容,而是创建新版本:
1 | |
更新服务:
1 | |
十五、使用 Stack 部署应用
虽然这篇文章不是讲 Compose,但 Swarm 的 docker stack deploy 会使用 Compose 文件格式来描述一组服务。
1. Stack 是什么?
Stack 是一组 Service、Network、Volume、Config、Secret 的集合。
如果 docker service create 是一个一个创建服务,docker stack deploy 就是一次部署一组服务。
2. 一个简单 Stack 示例
stack.yml:
1 | |
部署:
1 | |
查看 Stack:
1 | |
删除 Stack:
1 | |
3. 注意 stack deploy 和 Compose 的差异
docker stack deploy 使用的是 Swarm Stack 部署能力,它不是本地 docker compose up 的完全替代。
常见差异:
build通常不适合 stack 部署,生产应提前构建并推送镜像到 Registrycontainer_name在 Swarm 中不适合使用depends_on不提供 Compose 本地编排那种启动顺序语义deploy字段在 Swarm 中生效,而在很多本地 Compose 场景下行为不同- Stack 部署要在 Manager 节点执行
- 镜像必须能被所有节点拉取
4. 为什么生产要用私有镜像仓库?
如果你在 manager-1 本地 build 了镜像:
1 | |
然后部署:
1 | |
Task 可能被调度到 worker-1。
但 worker-1 上没有这个镜像,就会拉取失败。
生产流程应该是:
flowchart LR
A[构建镜像] --> B[推送到 Harbor / Registry]
B --> C[Swarm 部署 Service]
C --> D[各 Worker 从 Registry 拉取镜像]
示例:
1 | |
十六、部署 Spring Boot 到 Swarm
1. Dockerfile
1 | |
构建并推送:
1 | |
2. 创建 Overlay 网络
1 | |
3. 创建 Secret
1 | |
4. 部署服务
1 | |
5. 更新服务
1 | |
6. 查看状态
1 | |
7. 回滚
1 | |
十七、有状态服务和数据卷的坑
Swarm 跑无状态服务很舒服,但跑有状态服务要谨慎。
1. 本地 Volume 的问题
比如:
1 | |
这个 mysql-data 是每个节点本地的 volume。
如果 MySQL task 从 worker-1 漂移到 worker-2:
1 | |
结果可能是灾难。
2. 有状态服务的几种方案
| 方案 | 说明 |
|---|---|
| 固定节点运行 | 使用 placement constraint,把服务固定到某个节点 |
| 外部数据库 | 数据库不跑在 Swarm 里,使用云数据库或独立集群 |
| 分布式存储 | 使用 NFS、Ceph、GlusterFS、Longhorn 等 |
| 专业中间件集群 | MySQL 主从、Redis Cluster、Kafka 集群等单独规划 |
| Docker Volume Plugin | 使用支持多节点存储的插件 |
3. 使用节点标签固定 MySQL
给节点打标签:
1 | |
部署 MySQL:
1 | |
这可以避免 MySQL 随意漂移到其他节点。
但它不等于高可用。
worker-1 挂了,MySQL 还是不可用。
4. 推荐实践
生产环境建议:
- Web/API/Worker 这类无状态服务跑 Swarm
- MySQL/PostgreSQL/Redis/Kafka 等状态服务单独规划
- 小团队可以用固定节点 + 强备份
- 关键业务使用云数据库或专门的数据库集群
- 不要以为 Swarm 自动迁移就等于数据自动迁移
容器会漂移,数据不会自己长腿跟上。别给数据安排它做不到的事情。
十八、节点标签和调度约束
1. 给节点打标签
1 | |
查看:
1 | |
2. 使用约束部署服务
1 | |
3. 多约束
1 | |
4. 排除某些节点
1 | |
5. Global 服务
Global 服务会在每个符合条件的节点上运行一个 Task。
适合:
- 日志采集 Agent
- 监控 Agent
- 节点 Exporter
- 安全扫描 Agent
示例:
1 | |
6. Replicated vs Global
| 模式 | 说明 | 场景 |
|---|---|---|
| replicated | 指定副本数 | Web/API/Worker |
| global | 每个节点一个 | Agent/Exporter/日志采集 |
十九、节点维护:Drain、Pause、Active
节点有可用性状态:
| 状态 | 说明 |
|---|---|
| Active | 可以接收新 Task |
| Pause | 不接收新 Task,但已有 Task 继续运行 |
| Drain | 不接收新 Task,并迁移已有 Task |
1. Drain 节点
维护 worker-1 前:
1 | |
Swarm 会把 worker-1 上的 Task 调度到其他 Active 节点。
查看:
1 | |
2. 恢复节点
1 | |
注意:恢复 Active 后,Swarm 不一定立刻把 Task 迁回该节点。
Swarm 追求最小扰动,不会为了“看起来平均”随便迁移正在跑的任务。
如果需要强制重新分布:
1 | |
3. Pause 节点
1 | |
Pause 不会迁移已有 Task,只是不再接新 Task。
4. 维护流程建议
flowchart TB
A[准备维护节点] --> B[设置 Drain]
B --> C[等待 Task 迁移完成]
C --> D[确认服务副本正常]
D --> E[维护系统/升级 Docker/重启机器]
E --> F[节点恢复]
F --> G[设置 Active]
G --> H[观察集群状态]
二十、Swarm 安全机制
1. 节点间 mTLS
Swarm 内置 PKI。
节点加入 Swarm 时,Manager 会给节点签发证书。节点之间使用双向 TLS 认证和加密通信。
这比很多人想象的要完整。
Swarm 简单,不代表它在安全上裸奔。
2. Join Token
Swarm 有两类 token:
1 | |
Worker token 用于加入 Worker。
Manager token 用于加入 Manager。
Manager token 权限更高,必须保护好。
3. 轮换 Token
1 | |
如果 token 泄露,立即轮换。
4. 轮换 CA
如果 CA 或 Manager 被怀疑泄露:
1 | |
5. Auto-lock
Swarm 的 Raft 日志包含敏感数据,比如 Secret。
可以开启 auto-lock,保护 Manager 本地加密密钥。
初始化时开启:
1 | |
已有 Swarm 开启:
1 | |
查看 unlock key:
1 | |
Manager 重启后需要解锁:
1 | |
轮换 unlock key:
1 | |
注意:unlock key 必须安全保存。
别开启 auto-lock 后自己把钥匙丢了,那就是给自己集群上了一把精致的锁,然后把钥匙扔进了海里。
二十一、Swarm 备份与恢复
1. 需要备份什么?
Manager 节点的 Swarm 状态保存在:
1 | |
这里包含:
- Raft 日志
- 集群状态
- 网络对象
- 服务对象
- Secret/Config 元数据
- 加密相关 key
2. 备份 Swarm 状态
建议停止 Docker 后备份,避免状态变化。
1 | |
如果开启了 auto-lock,记得保存 unlock key:
1 | |
3. 恢复 Swarm
恢复到新 Manager:
1 | |
如果需要强制形成新集群:
1 | |
4. 丢失 Quorum 怎么办?
如果 Manager 多数派丢失,集群不能执行管理操作:
- 不能创建服务
- 不能更新服务
- 不能扩缩容
- 不能添加节点
- 不能删除节点
但已有 Worker 上的任务可能继续运行。
恢复优先级:
- 尽量恢复原 Manager 节点。
- 如果无法恢复,在保留完整状态的 Manager 上执行
--force-new-cluster。 - 重新加入 Manager 和 Worker。
- 检查服务状态。
- 重新建立备份策略。
命令:
1 | |
二十二、监控与日志
Swarm 原生可以查看服务状态,但生产还需要监控系统。
1. 常用原生命令
查看节点:
1 | |
查看服务:
1 | |
查看任务:
1 | |
查看日志:
1 | |
查看节点详情:
1 | |
查看服务详情:
1 | |
2. 监控建议
常用组合:
- Prometheus
- Grafana
- cAdvisor
- Node Exporter
- Alertmanager
Node Exporter 适合 global 模式:
1 | |
cAdvisor 示例:
1 | |
注意:这些监控容器通常要挂载宿主机目录,权限较高,要控制访问。
3. 日志建议
Swarm 里的服务日志可以用:
1 | |
但生产更推荐集中日志:
- Loki + Promtail
- ELK / EFK
- Fluent Bit
- Vector
- Graylog
日志采集 Agent 适合 global 模式,每个节点一个。
二十三、Swarm 常见故障排查
1. 节点 Not Ready
查看节点:
1 | |
排查:
1 | |
检查端口:
1 | |
检查 UDP 端口需要用专门工具,例如 nc -u 或 tcpdump。
2. 服务一直 Pending
查看:
1 | |
常见原因:
- 节点资源不足
- placement constraint 无节点满足
- 镜像拉取失败
- 私有仓库未登录
- 端口冲突
- 网络创建失败
- Secret/Config 不存在
3. 镜像拉取失败
如果使用私有仓库,所有节点都要能拉取镜像。
每个节点登录:
1 | |
或者使用:
1 | |
更新服务:
1 | |
4. 服务端口访问不了
检查:
1 | |
检查端口发布:
1 | |
检查防火墙:
1 | |
5. Overlay 网络不通
检查端口:
- 7946 TCP/UDP
- 4789 UDP
查看网络:
1 | |
抓包:
1 | |
6. Manager Unreachable
查看:
1 | |
查看 Docker 日志:
1 | |
检查 Manager 之间网络:
1 | |
如果 Manager 长期不可恢复:
1 | |
注意保持 quorum。
7. 服务没有重新均衡
Swarm 不会为了平均而随便迁移正在运行的任务。
如果新增节点后想重新分布:
1 | |
或滚动更新服务。
二十四、生产部署架构建议
1. 推荐架构
flowchart TB
LB[外部负载均衡器 Nginx/HAProxy/云LB] --> N1[manager-1 / worker]
LB --> N2[worker-1]
LB --> N3[worker-2]
subgraph Swarm[Docker Swarm Cluster]
M1[manager-1]
M2[manager-2]
M3[manager-3]
W1[worker-1]
W2[worker-2]
W3[worker-3]
M1 <-->|Raft| M2
M2 <-->|Raft| M3
M1 <-->|Raft| M3
W1 --> APP1[app task]
W2 --> APP2[app task]
W3 --> APP3[app task]
end
REG[Harbor / Registry] --> Swarm
DB[(外部数据库)]
APP1 --> DB
APP2 --> DB
APP3 --> DB
2. 节点规划建议
| 环境 | Manager | Worker | 说明 |
|---|---|---|---|
| 测试 | 1 | 0-2 | 可以单节点 |
| 小生产 | 3 | 2+ | 起步推荐 |
| 中等生产 | 3 或 5 | 多个 | Manager 分散部署 |
| 高可用 | 5 | 多个 | 跨可用区部署 |
3. Manager 分布建议
3 Manager:
1 | |
5 Manager:
1 | |
4. 服务部署建议
- 无状态服务使用 replicated
- Agent 类服务使用 global
- 重要服务设置资源限制
- 服务设置 update/rollback 策略
- 使用 overlay 网络隔离业务
- 使用 Secret 管理敏感信息
- 使用 Config 管理配置文件
- 使用 Harbor/Registry 分发镜像
- 数据库优先外置
- 生产入口优先使用外部 LB + Swarm 服务
5. 命名规范建议
Service:
1 | |
Network:
1 | |
Secret:
1 | |
Config:
1 | |
二十五、完整实战:部署一个 API 集群
假设我们有:
- Spring Boot API
- 镜像:
harbor.example.com/backend/demo-api:1.0.0 - 对外端口:8080
- 副本数:3
- 使用 Secret 读取数据库密码
- 使用 Overlay 网络
- 使用滚动更新和失败回滚
1. 创建网络
1 | |
2. 创建 Secret
1 | |
3. 部署服务
1 | |
4. 查看状态
1 | |
5. 扩容
1 | |
6. 发布新版本
1 | |
7. 回滚
1 | |
8. 更新 Secret
1 | |
1 | |
确认正常后:
1 | |
二十六、使用 Stack 部署完整应用
demo-stack.yml:
1 | |
创建 Secret:
1 | |
给节点打标签:
1 | |
部署:
1 | |
查看:
1 | |
删除:
1 | |
二十七、Docker Swarm 常用命令清单
1. Swarm 集群
1 | |
2. 节点管理
1 | |
3. 服务管理
1 | |
4. 网络管理
1 | |
5. Secret 管理
1 | |
6. Config 管理
1 | |
7. Stack 管理
1 | |
二十八、自动化脚本合集
1. 初始化 Manager
init-manager.sh:
1 | |
2. 打印 Join Token
show-tokens.sh:
1 | |
3. 节点巡检
swarm-check.sh:
1 | |
4. 服务发布脚本
deploy-service.sh:
1 | |
5. Swarm 备份脚本
backup-swarm.sh:
1 | |
6. 节点维护脚本
drain-node.sh:
1 | |
active-node.sh:
1 | |
二十九、Docker Swarm 和 Kubernetes 对比
1. 对比表
| 对比项 | Docker Swarm | Kubernetes |
|---|---|---|
| 上手难度 | 低 | 高 |
| 与 Docker CLI 集成 | 原生 | 间接 |
| 单机到集群迁移 | 简单 | 复杂一些 |
| 网络模型 | Overlay + Routing Mesh | CNI |
| 服务发现 | 内置 DNS/VIP | Service/CoreDNS |
| 配置管理 | Config/Secret | ConfigMap/Secret |
| 滚动更新 | 支持 | 支持且更强 |
| 自动伸缩 | 弱 | 强 |
| 生态 | 较小 | 极强 |
| Operator | 基本没有 | 丰富 |
| 多租户治理 | 弱 | 强 |
| 学习成本 | 低 | 高 |
| 适合场景 | 中小集群、简单编排 | 大规模云原生平台 |
2. 什么时候选 Swarm?
选择 Swarm,如果你:
- 已经熟悉 Docker
- 服务规模不大
- 希望快速搭一个可用集群
- 不想引入 K8s 学习和维护成本
- 主要跑无状态服务
- 团队没有专职平台工程能力
- 更重视简单、直接、够用
3. 什么时候选 Kubernetes?
选择 Kubernetes,如果你:
- 有复杂微服务治理需求
- 有大规模集群
- 要使用云原生生态
- 需要 HPA、Operator、CRD
- 需要复杂网络和存储插件
- 需要完善多租户和策略治理
- 团队具备 K8s 运维能力
4. 一句实话
很多团队不是需要 Kubernetes,而是想显得自己需要 Kubernetes。
如果只是几个 Spring Boot 服务、一个 Redis、一个 MySQL、一个 Nginx,上来就 K8s,可能还没服务出问题,集群自己先开始教育你。
Swarm 的价值在于:
它把多机容器编排做到足够简单。
但如果你的系统已经复杂到 Swarm 不够用,就不要硬撑,该上 Kubernetes 就上 Kubernetes。
三十、生产实践检查清单
1. 集群规划
- Manager 使用固定 IP
- Manager 数量为 3 或 5
- Manager 分布在不同可用区或不同物理机
- Worker 资源足够
- 防火墙开放 2377、7946、4789
- 业务端口按需开放
- 节点时间同步正常
2. 安全
- 保护 manager join token
- 定期轮换 join token
- 使用 Secret 管理敏感数据
- 不把密码写进镜像和环境变量
- 关键集群开启 auto-lock
- 私有 Registry 使用 HTTPS
- 所有节点使用可信镜像仓库
- 限制 Docker Socket 访问
3. 服务部署
- 使用私有镜像仓库
- 镜像 tag 明确,不滥用 latest
- 配置 update 和 rollback 策略
- 配置资源限制
- 无状态服务多副本
- 有状态服务固定节点或外置
- 使用节点 label 管理调度
- 使用 overlay 网络隔离服务
4. 运维
- 配置集中日志
- 配置监控和告警
- 定期备份
/var/lib/docker/swarm - 保存 auto-lock unlock key
- 定期演练恢复
- 节点维护前先 Drain
- 变更前确认 quorum
- 记录服务部署配置
5. 排错
- 会使用
docker node ls - 会使用
docker service ps --no-trunc - 会使用
docker service logs - 会检查 overlay 网络端口
- 会处理镜像拉取失败
- 会排查 placement constraint
- 会恢复 quorum
总结
Docker Swarm 是 Docker 原生的集群编排能力。
它的核心不是“多台机器跑容器”这么简单,而是围绕 Service 的期望状态进行调度和维护:
- 你声明服务应该是什么状态
- Manager 把状态写入 Raft
- Scheduler 把 Task 分配到节点
- Worker 运行容器
- 节点故障后重新调度
- 服务更新时滚动替换
- 入口流量通过 Routing Mesh 转发
- 服务之间通过 Overlay 网络通信
- Secret 和 Config 由 Swarm 管理
Swarm 的优点很明确:
- 简单。
- Docker 原生。
- CLI 统一。
- 上手快。
- 适合中小规模。
- 比 Compose 更适合多机。
- 比 Kubernetes 更轻量。
Swarm 的短板也要诚实面对:
- 生态没有 Kubernetes 丰富。
- 自动伸缩能力弱。
- 存储编排能力有限。
- 复杂服务治理能力有限。
- 大规模平台化不如 Kubernetes。
所以最合理的态度是:
小规模别强上 Kubernetes,大规模别硬撑 Swarm。
如果你要的是简单、稳定、Docker 原生、多机编排,Docker Swarm 依然是一个很实用的选择。
如果你已经需要复杂云原生生态、Operator、多租户、自动伸缩和精细化策略,那么 Kubernetes 才是更长期的路线。
最后记住三句话:
- Manager 保持奇数,Quorum 是 Swarm 的命根子。
- 无状态服务适合 Swarm,有状态服务要认真规划存储。
- Swarm 很简单,但生产环境的网络、安全、备份、监控一点都不能简单。
参考资料
- Docker Docs: Swarm mode
https://docs.docker.com/engine/swarm/ - Docker Docs: Swarm mode key concepts
https://docs.docker.com/engine/swarm/key-concepts/ - Docker Docs: How nodes work
https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/ - Docker Docs: How services work
https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/ - Docker Docs: Create a swarm
https://docs.docker.com/engine/swarm/swarm-tutorial/create-swarm/ - Docker Docs: Add nodes to the swarm
https://docs.docker.com/engine/swarm/swarm-tutorial/add-nodes/ - Docker Docs: Deploy services to a swarm
https://docs.docker.com/engine/swarm/services/ - Docker Docs: Use Swarm mode routing mesh
https://docs.docker.com/engine/swarm/ingress/ - Docker Docs: Overlay network driver
https://docs.docker.com/engine/network/drivers/overlay/ - Docker Docs: Manage sensitive data with Docker secrets
https://docs.docker.com/engine/swarm/secrets/ - Docker Docs: Store configuration data using Docker Configs
https://docs.docker.com/engine/swarm/configs/ - Docker Docs: Apply rolling updates to a service
https://docs.docker.com/engine/swarm/swarm-tutorial/rolling-update/ - Docker Docs: Drain a node on the swarm
https://docs.docker.com/engine/swarm/swarm-tutorial/drain-node/ - Docker Docs: Deploy a stack to a swarm
https://docs.docker.com/engine/swarm/stack-deploy/ - Docker Docs: Administer and maintain a swarm of Docker Engines
https://docs.docker.com/engine/swarm/admin_guide/ - Docker Docs: Manage swarm security with PKI
https://docs.docker.com/engine/swarm/how-swarm-mode-works/pki/