共计 5255 个字符,预计需要花费 14 分钟才能阅读完成。
文章目录 [显示]
还记得小时候搬东西吗?一个人搬一台冰箱,累得半死还搬不动。但叫上三五个兄弟,嘿,轻轻松松就上了五楼。Docker Swarm 干的就是这事儿——把一群 " 单打独斗 " 的服务器组织成一个团队,让它们像一台超级计算机一样协同工作。
当你的应用从日均 100 访问量涨到 10 万,单机扛不住了怎么办?加内存?换 CPU?这叫纵向扩展,迟早有天花板。真正的出路是横向扩展——多搞几台机器一起干活。而 Docker Swarm 就是帮你把这些机器 " 拧成一股绳 " 的工具。
本文你将学到
- Swarm 集群的核心架构和角色分工
- 如何用两条命令组建一个集群
- Service 的创建、扩缩容和滚动更新
- Swarm 内置负载均衡的工作原理
- 生产环境常见问题排查
阅读时间:12 分钟 | 实操时间:30 分钟 | 难度等级:中级
一、Swarm 是什么?先看架构
用一个比方来理解:Swarm 集群就像一个施工队。有个工头(Manager)负责接活、分配任务、盯进度;还有一帮工人(Worker)负责埋头干活。工头自己也可以干活,但主要职责是管理。
来看整体架构:
┌─────────────────────────────────┐
│ Swarm 集群 │
│ │
│ ┌──────────┐ │
用户请求 ──┤──>│ Manager │ (调度 + Raft 共识) │
│ └────┬─────┘ │
│ │ 任务分发 │
│ ┌────┴─────────────┐ │
│ │ │ │ │ │
│ v v v v │
│ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │
│ │W1│ │W2│ │W3│ │W4│ │
│ └──┘ └──┘ └──┘ └──┘ │
│ Worker Worker Worker Worker │
└─────────────────────────────────┘
核心概念
| 概念 | 说明 | 类比 |
|---|---|---|
| Node | 集群中的一台机器 | 施工队的一个人 |
| Manager | 管理节点,负责调度和状态维护 | 工头 |
| Worker | 工作节点,负责运行容器 | 工人 |
| Service | 你要运行的应用定义 | 一份施工图纸 |
| Task | Service 分配到具体节点的实例 | 图纸分配给某个工人的具体任务 |
| Raft | Manager 之间的共识协议 | 工头们开会投票做决定 |
一个关键设计:Manager 节点之间通过 Raft 协议保持数据一致。生产环境建议 3 个或 5 个 Manager(奇数个,方便投票不打平手)。Worker 想加多少加多少。
二、动手组建集群
我们用三台机器来演示。没有三台机器?没关系,用 docker-machine 或者直接开三个虚拟机都行。这里假设你有三台机器:
node1: 192.168.1.10 (Manager)
node2: 192.168.1.11 (Worker)
node3: 192.168.1.12 (Worker)
2.1 初始化 Swarm(在 node1 上执行)
docker swarm init --advertise-addr 192.168.1.10
预期输出:
Swarm initialized: current node (abc123def456) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-xxxxx 192.168.1.10:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
就这一条命令,集群就建好了。Docker 会生成一个 token,其他机器拿着这个 token 来 " 入伙 "。
2.2 Worker 加入集群(在 node2 和 node3 上执行)
复制上面输出的 join 命令:
docker swarm join --token SWMTKN-1-xxxxx 192.168.1.10:2377
预期输出:
This node joined a swarm as a worker.
2.3 查看集群状态(在 Manager 上执行)
docker node ls
预期输出:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
abc123def456 * node1 Ready Active Leader
ghi789jkl012 node2 Ready Active
mno345pqr678 node3 Ready Active
三个节点,一个 Leader(Manager),两个 Worker。集群就绑好了,比配置 Kubernetes 简单多了吧?
三、部署 Service
集群有了,该在上面跑应用了。在 Swarm 里,你不直接运行容器,而是创建 Service。Service 是 " 声明式 " 的——你告诉 Swarm" 我要 3 个 Nginx 实例 ",它帮你安排到合适的节点上。
3.1 创建一个 Service
docker service create \
--name web \
--replicas 3 \
--publish 80:80 \
nginx:alpine
预期输出:
qrs901tuv234
overall progress: 3 out of 3 tasks
1/3: running [==================================================>]
2/3: running [==================================================>]
3/3: running [==================================================>]
verify: Service converged
三个 Nginx 副本被分配到了三个节点上。
3.2 查看 Service 状态
docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
qrs901tuv234 web replicated 3/3 nginx:alpine *:80->80/tcp
查看每个副本运行在哪个节点:
docker service ps web
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
aaa111 web.1 nginx:alpine node1 Running Running 2 minutes ago
bbb222 web.2 nginx:alpine node2 Running Running 2 minutes ago
ccc333 web.3 nginx:alpine node3 Running Running 2 minutes ago
3.3 弹性扩缩容
流量突然涨了?加副本:
docker service scale web=5
流量回落了?缩回来:
docker service scale web=2
就这么简单。Swarm 会自动在可用节点上分配或回收容器。
四、滚动更新
应用要升级版本了,总不能停服吧?Swarm 支持滚动更新——一个一个换,用户完全无感知。
4.1 执行滚动更新
假设要把 Nginx 从 alpine 更新到最新版:
docker service update \
--image nginx:latest \
--update-parallelism 1 \
--update-delay 10s \
web
这条命令的意思是:每次更新 1 个副本,更新完等 10 秒再更新下一个。
更新过程中可以实时查看:
docker service ps web
你会看到旧副本逐个被新副本替换。
4.2 更新出问题?回滚
如果新版本有 Bug,一条命令回滚:
docker service rollback web
Swarm 会自动把所有副本回退到上一个版本。这就像游戏里的存档读档,关键时刻能救命。
你也可以在创建 Service 时就配好自动回滚策略:
docker service create \
--name web \
--replicas 3 \
--update-failure-action rollback \
--update-max-failure-ratio 0.3 \
nginx:alpine
意思是:如果超过 30% 的副本更新失败,自动回滚。
五、内置负载均衡
Swarm 有个很贴心的设计叫 Routing Mesh(路由网格)。你访问集群中任意节点的 80 端口,Swarm 都会自动把请求转发到运行了该 Service 的节点上。
用户请求 :80
│
┌────────┼────────┐
v v v
node1 node2 node3
(web.1) (web.2) (web.3)
即使某个节点上没有运行对应的容器,请求打到这个节点也照样能处理——Swarm 内部会帮你转发。这意味着你可以把任意节点的 IP 挂到负载均衡器后面,不用关心容器具体跑在哪儿。
验证一下:
# 在任意节点上执行,都能访问到 Service
curl http://192.168.1.10
curl http://192.168.1.11
curl http://192.168.1.12
三个地址都能返回 Nginx 欢迎页。
六、实战:部署一个完整应用
来个实际的例子,部署一个带 Redis 后端的 Web 应用:
# 先创建一个 overlay 网络(跨节点通信)docker network create --driver overlay app-net
# 部署 Redis
docker service create \
--name redis \
--network app-net \
--replicas 1 \
redis:alpine
# 部署 Web 应用
docker service create \
--name app \
--network app-net \
--replicas 3 \
--publish 8080:5000 \
--env REDIS_HOST=redis \
my-web-app:latest
注意这里用了 overlay 网络。这是 Swarm 的跨节点网络方案——不管容器跑在哪台机器上,通过 overlay 网络都能互相访问。Service 名字(redis)直接当域名用,Swarm 内置了 DNS 解析。
七、常见问题 Q&A
Q1:Manager 挂了怎么办?
如果是单 Manager,那就完蛋了(集群不可管理,但已运行的容器不受影响)。所以生产环境至少 3 个 Manager。Raft 协议能容忍 (N-1)/2 个节点故障——3 个 Manager 允许挂 1 个,5 个允许挂 2 个。
添加 Manager 节点:
# 在现有 Manager 上获取 token
docker swarm join-token manager
# 在新节点上执行返回的命令
docker swarm join --token SWMTKN-1-manager-token 192.168.1.10:2377
Q2:Worker 挂了,上面的容器怎么办?
Swarm 会自动在其他可用节点上重新调度这些容器。比如你有 3 个副本分布在 3 个 Worker 上,其中一个 Worker 挂了,Swarm 会在剩余 2 个 Worker 上启动新副本,始终保持 3 个副本运行。
Q3:Swarm 和 Kubernetes 怎么选?
简单说:小团队、中小规模(几十个节点以内)用 Swarm,够用且运维成本低;大规模、复杂编排需求用 Kubernetes。Swarm 的优势是 " 零配置 "——Docker 内置,不需要额外装任何东西。Kubernetes 功能强大但学习曲线陡峭。先用 Swarm 跑起来,等真到了 Swarm 撑不住的那天再迁移也不迟。
八、管理命令速查
# 集群管理
docker swarm init # 初始化集群
docker swarm join # 加入集群
docker swarm leave # 离开集群
docker swarm leave --force # Manager 强制离开
# 节点管理
docker node ls # 列出所有节点
docker node inspect # 查看节点详情
docker node promote # Worker 升级为 Manager
docker node demote # Manager 降级为 Worker
docker node rm # 移除节点
# Service 管理
docker service create # 创建服务
docker service ls # 列出服务
docker service ps # 查看服务任务
docker service logs # 查看服务日志
docker service scale =N # 扩缩容
docker service update # 更新服务
docker service rollback # 回滚服务
docker service rm # 删除服务
小结
今天我们把 Docker 从 " 单机 " 推向了 " 集群 "。核心就三件事:
- 组建集群 :
swarm init+swarm join,两条命令搞定 - 部署服务 :
service create声明式部署,自动调度到合适节点 - 滚动更新 :
service update无缝升级,出问题一键回滚
Swarm 的设计哲学和 Docker 一脉相承——简单够用。它不像 Kubernetes 那样什么都能干,但对于大多数中小项目来说,它就是那个 " 刚刚好 " 的方案。
明天 Day 27,我们聊聊生产部署策略——怎么把开发环境的容器安全、高效地推到线上去,包括 CI/CD 流水线、镜像管理和部署最佳实践。这是从 " 会用 Docker" 到 " 用好 Docker" 的关键一步。