1. 为什么要学 Swarm:掉进编排这个大坑之前,先想明白
先说一个我自己的经历。两三年前我用 Docker 管项目,还是典型的“一台机器打天下”思路:docker-compose up -d一把梭,容器想开几个开几个,数据库、后端、前端全堆在一台服务器上。刚开始小项目没啥问题,后来接了仿真计算任务,一台 1U 服务器顶不住,第二台机器来了,噩梦也就开始了。两台机器之间怎么协同?第二台机器的服务怎么发现第一台机器的数据库?服务扩容到 10 个副本,流量怎么分流?负载高了我怎么知道该扩哪台机器?我试着用docker-compose配一个跨主机网络,配了一晚上没搞定,头都快秃了。
这时候我把目光转向容器编排,紧接着就看到两个名字:Kubernetes 和 Docker Swarm。当时我身边一堆人讨论 Kubernetes,觉得不会 K8s 就不算懂容器,但 Swarm 反而被归类为“玩具”“快过时了”。后来我同时在两台测试环境里分别搭了 K8s 和 Swarm,真正跑业务之后才意识到:Docker Swarm 不是玩具,它是那种“90% 的场景够用、配置简单到令人发指、维护成本低到离谱”的工具。本篇文章就来聊聊 Docker 进阶系列的第二个大主题:Swarm 编排。
这篇文章适合谁?如果你已经能熟练使用docker run和docker-compose,但还没接触过生产级容器调度;如果你在犹豫 Kubernetes 和 Swarm 之间到底该学哪个;如果你手头有 3 到 5 台服务器,需要一个不劝退的集群方案。这篇文章就是为你准备的。我会把我在这条路上踩过的坑、摸索出来的命令、以及一些官方文档里不会写但你敢信就省时间的经验全部掏出来。
先说结论:Swarm 是 Docker 官方内置的容器编排方案,它和 Docker 生态无缝融合,能用几条命令就把多台 Docker 主机组成一个“逻辑上像一台电脑”的集群。你在这台虚拟“大电脑”上发布的容器服务,它会自动帮你调度到空闲节点、自动做负载均衡、自动管理副本数、自动滚动更新。虽然它的功能丰富度不如 Kubernetes,但它的上手复杂度、运维复杂度只有 Kubernetes 的十分之一。在我看来,中小型项目、内部系统、个人生产的首选编排工具,Swarm 当之无愧。
2. 核心架构拆解:Manager、Worker 和那个你以为“无所谓”的 Raft
2.1 三句话讲明白整体设计
Swarm 集群由两类节点组成:管理节点(Manager Node)和工作节点(Worker Node)。管理节点就是“集群大脑”,所有docker service命令都得打在管理节点上,由它决定容器跑到哪台机器;工作节点是“干活的手”,只运行你发布出来的容器实例,等着管理节点给它派任务。
每个节点上,Swarm 都会运行一个 agent 进程,管理节点上多一个调度器组件。整个架构和公司组织很像:老板(Manager)不亲自写代码,只负责接单分活;员工(Worker)不跟客户开会,只管把活干完。而那个容易被人忽略的 Raft 一致性协议,就是保证管理节点之间“说话算数”的关键。
2.2 Manager 节点数量到底选几个,单 Manager 会怎样?
不少新手拿到 Swarm 之后第一步就是docker swarm init,默认创建 1 个 Manager,然后把所有机器join进来。大哥,这跟没上集群有什么区别?管理节点是单点,这机器挂了,整个 Swarm 集群的调度能力就挂了,虽然已有的容器服务还在跑,但你想扩缩容、更新镜像、查看集群状态,全部没门。
生产环境里我建议管理节点至少 3 个,原因是 Raft 算法的投票机制:在 N 个管理节点的集群中,至少要有(N/2)+1个节点在线才能形成法定人数。3 个 Manager 可以容忍 1 个挂掉;5 个 Manager 可以容忍 2 个挂掉。你可能会问:为什么不能搞 2 个?2 个 Manager 如果挂掉 1 个,剩下 1 个不足法定人数,整个集群会直接瘫痪,反倒比单 Manager 更危险。所以要么只设置 1 个用在测试环境图省事,要么就 3 个起步,千万别取中间数。
2.3 Raft 分担了什么?服务状态和配置的“日志账本”
Swarm 把集群里所有状态变更——哪个服务需要扩容、某节点状态是 Ready 还是 Down、服务更新到什么版本——全部记录在 Raft 日志里。这些日志在 Manager 节点之间同步复制,多数管理节点确认后才会生效。
实际运维里,Raft 常被低估,但如果你想做“花式操作”,比如把一个 Manager 节点分离开来专门做监控,这就涉及 Raft 的角色调整。有一个操作叫docker node demote,可以把 Manager 降级为 Worker,降级之后它会立即停止参与 Raft 投票。集群里 Manager 数量低于法定人数时,你不能随便 demote,否则整个集群自己就先把调度锁住了。我曾经在测试环境里只有 2 个 Manager,一年轻小伙子手快把 1 个 Manager demote 了,集群当场“脑裂”,业务调用链瞬间全断。就在那天,我深刻记住了法定人数这个数学要求。
3. 实操开始:从零搭建一个三节点 Swarm 集群
3.1 准备阶段:机器、版本与端口
先明确实验环境。我自己用三台 Ubuntu 20.04 虚拟机模拟,主机名分别叫 node1、node2、node3,其中 node1 作为初始管理节点。每台机器上安装 Docker,版本至少 20.10 以上。这里有个细节:Docker Engine 自带 swarm 模式,不需要额外装插件,这是 Swarm 最大的优势之一,开箱即用。
Swarm 集群默认用到几个关键端口,防火墙如果开了,一定记得放行:
| 端口 | 作用 |
|---|---|
| 2377/tcp | 集群管理通信,节点加入、Raft 同步都走它 |
| 7946/tcp/udp | 节点间通信 |
| 4789/udp | VXLAN overlay 网络数据面 |
很多第一次搭集群的人把命令敲完,docker node ls就是看不到新节点,排查半天发现是云厂商安全组没放开 7946 端口,这种低级坑我踩过不止一次。对,云厂商的控制台安全组和机器内部防火墙是两套系统,两边都要检查。
3.2 初始化集群:一句话命令
登录 node1,执行:
docker swarm init --advertise-addr 192.168.1.11这里的--advertise-addr非常重要。它告诉其他节点“你要通过这个地址来找我”。如果你的机器有多个网卡,例如一个公网网卡一个内网网卡,不加这个参数 Swarm 可能会选错网卡,导致其他节点根本无法与它握手。测试环境里我直接填 node1 的内网 IP。
初始化成功后,终端会输出一段docker swarm join --token <token> 192.168.1.11:2377。这个 token 是加入集群的凭证,分两种,一种是管理节点 token,一种是工作节点 token。用docker swarm join-token worker可以单独查看工作节点的加入命令,docker swarm join-token manager查看管理节点的。
3.3 节点加入:证书、加密与秒级完成
登录 node2 和 node3,分别执行刚才输出的 join 命令。如果要加入为 Manager,就用 manager token 的命令。默认 Swarm init 后,第一个节点既是 Manager 也是 Worker,可以承担容器调度任务,但我建议生产环境把 Manager 和 Worker 角色分离:Manager 只干调度,不跑业务容器,这样资源争抢和故障影响都能隔离开。
加入完成后,回到 node1 上执行:
docker node ls你应该能看到三个节点状态都是 Ready,Manager 一列中 node1 和 node2、node3(如果加入的是 Manager)都会是 Reachable 或 Leader。这里有个常见疑问:为什么 Manager 节点的状态不是 Leader 而是 Reachable?很简单,Leader 只有一个,是 Raft 选出来的主节点,其他 Manager 都是 Reachable,随时准备接替。
3.4 标记节点角色和在业务中的实际用途
节点加进来之后,我喜欢立刻给它们打标签,也就是node label。标签在服务调度时能做约束,比如有些服务只允许跑在 SSD 节点上,有些服务必须离数据库近。命令长这样:
docker node update --label-add type=ssd node2 docker node update --label-add type=hdd node3然后在服务创建时加上约束:
docker service create \ --name nginx \ --constraint node.labels.type==ssd \ nginx:latest这个操作很像docker-compose里的deploy.placement.constraints,但在 Swarm 里是集群维度的,跨节点生效。我在某公司做数据服务时,经常用标签把 CPU 密集型和内存密集型服务分开调度,避免互相抢占资源,非常实用。
4. 服务部署:把 docker-compose 改成 docker service 的思考转变
4.1 服务是首选抽象,容器只是它的实例
使用 Swarm 之后,你要转变一个思考习惯:不再说“我要运行一个容器”,而是说“我要发布一个服务”。服务(Service)是 Swarm 中的一等公民,它描述了“我要多少个副本”“用什么镜像”“暴露哪些端口”“内存 CPU 限制是多少”,然后 Swarm 负责确保现实世界始终与这个描述一致。如果某个节点宕机,Swarm 会自动在别的节点上重新拉起丢失的副本,不需要人肉干预。相比裸跑 Docker 容器,这是质的飞跃。
4.2 第一个服务:发布 Nginx 并验证路由网格
在 Manager 节点上执行:
docker service create \ --name web \ --publish published=8080,target=80 \ --replicas 3 \ nginx:1.25然后查看服务状态:
docker service ls docker service ps webdocker service ps web会显示 3 个副本,以及它们分别被调度到了哪个节点。接下来是 Swarm 最让人满意的功能之一:路由网格(Routing Mesh)。任何节点上的 8080 端口,都能访问到这个服务,哪怕那个节点上根本没有这个服务的副本。你在浏览器里分别访问三台机器的http://IP:8080,都能得到 Nginx 的欢迎页。此举从根本上解决了“服务部署在某台机器,用户应该访问哪台机器”的问题,因为整个集群对外就是一个负载均衡器。
路由网格的原理是:Swarm 在集群内部维护了一个 ingress overlay 网络,每个发布端口的服务都会挂到这个网络上,集群内部所有节点都在监听这个端口,流量进来后被转发到具体某个副本。你可以认为,Swarm 自动帮你做了四层负载均衡。如果你需要七层 HTTP 反向代理,再部署一个容器化的 Nginx 或 Traefik,挂在路由网格前面,就非常接近生产架构了。
4.3 用 Stack 文件管理多服务:Compose 文件直接起飞
如果你已经习惯docker-compose管理多个容器,Swarm 对你是极度友好的。你写的docker-compose.yml文件不需要大改,把version保留,去掉services下的container_name,增加deploy字段,然后执行:
docker stack deploy -c docker-compose.yml myappStack 是 Swarm 对多服务组合应用的管理单位,一条命令即可创建或更新整个应用。我更倾向于把docker-compose.yml文件当作项目主配置,让 Swarm 兼容这个格式,因为它让团队协作型项目迁移到 Swarm 的成本几乎为零。比如我接过一个小型内部业务系统,落地时直接把开发写的 Compose 文件拿过来,在deploy里补上replicas: 2和update_config,灌进 Swarm,十分钟搞定,代码不用改一行。
4.4 secrets 配置:把数据库密码从镜像里抠出来
大部分新手很容易把数据库密码直接写在代码或环境变量里,镜像一构建就泄漏了。Swarm 提供了 secrets 机制,是 Docker 17.06 之后很亮眼的功能。
创建方法:
echo "MyDBPass123" | docker secret create db_password -然后服务里引用:
docker service create \ --name api \ --secret db_password \ --env DB_PASSWORD_FILE=/run/secrets/db_password \ api:latestSecret 的存放位置是容器内的/run/secrets/,Swarm 保证只有被授权的服务才能访问对应的 secret。生产环境里我一般把数据库密码、第三方 API Key、JWT 签名密钥统统放进 secrets,比环境变量安全得多,而且更新 secrets 时可以滚动重启服务,不必重新构建镜像。这个小功能光是省下的镜像构建时间都值回票价了。
5. 副本扩缩容与滚动更新:生产环境最常用的两把刀
5.1 手动扩缩容:一条命令告别“流量来了手忙脚乱”
业务流量上来了,最简单的方式:
docker service scale web=5对,就是这样五秒完成扩容。Swarm 的调度器会看集群资源现状,自动挑 2 台最空闲的机器启动新副本。反过来流量回落了,缩容到 3:
docker service scale web=3缩容时会先停掉一些健康副本,具体停哪几个由调度器决定,这个选择逻辑不是随机,而是基于节点的资源指标和维护状态。实际经验:不要在高峰期频繁修改副本数,Swarm 的调度与路由网格同步需要几秒,短时间内反复 scale 容易造成旧副本没销毁完成、新副本又启动的“抖动”,在监控图上看到一条锯齿线,吓到同事,实际上是操作太勤。
5.2 自动扩缩容:未雨绸缪的进阶玩法
Swarm 原生其实没有像 Kubernetes HPA 那样的自动伸缩组件,但我们可以用docker service update结合外部监控脚本实现。我常用的思路是:保留一个指标采集脚本,每 30 秒查询一次服务平均 CPU 或请求延迟,当超过阈值就调高--replicas,低于阈值就调低。
这里要特别提醒:自动扩缩容脚本务必设置冷却时间(Cooldown),比如扩容操作后至少等待 5 分钟才允许下一次扩缩容。原因在于容器在节点上启动到能对外服务是需要时间的,过于频繁的扩缩容不但不能缓解高峰,反而会造成资源碎片。我自己写过一版没有冷却时间的脚本,结果高峰期打满 CPU,扩容指令疯狂下发,新容器启动速度跟不上,容器互相争抢,服务反而雪崩,后来加上冷却时间才好。
5.3 滚动更新:让业务不中断的关键设置
镜像更新,在 Swarm 里的标准操作是:
docker service update \ --image nginx:1.26 \ --update-delay 30s \ --update-parallelism 1 \ --update-failure-action rollback \ web这个命令的内涵值得好好解释:
--update-delay 30s:每更新一个副本后,等待 30 秒再更新下一个,给新副本留出启动和自检的时间。--update-parallelism 1:同时更新的副本数,设为 1 就是一台一台换,如果设为 5 就是一批一批换。业务量大的场景可以适度提高并行度,但不要超过集群容量的 30%,否则更新期间整个集群的负载能力会明显下降。--update-failure-action rollback:更新过程中一旦发现新副本启动失败或健康检查不通过,立刻回滚到旧版本,这个参数我建议永远别去掉。
滚动更新的原理是 Swarm 会为每个服务维持一个“期望状态”,更新时它新建新版本的 Task,等它在启动中变成 Running 并成功通过健康检查,再销毁旧 Task。这也解释了为什么建议在服务里配置健康检查:没有健康检查,Swarm 只能靠进程是否退出判断容器死活,只要你镜像里的进程活着就不能判定失败,更新就会继续走下去,如果内部存在明显 bug 而不退出进程,就会把故障扩散到全部副本。
命令示例:
docker service create \ --name api \ --health-cmd "curl -f http://localhost/health || exit 1" \ --health-interval 10s \ --health-retries 3 \ --health-start-period 20s \ api:1.0这个健康检查配置,相当于给 Swarm 一双“能看懂业务是否正常”的眼睛。--health-start-period千万别理解成“启动后等 20 秒再检查”,它真正含义是在容器启动时留出初始化时间,在这段时间内即使健康检查失败,也不会立刻把容器标记为不健康。新手很容易把这种启动初始化时间算错,导致新容器每次起来还没就绪就被打上不健康标签,滚动更新必然反复回滚。
6. 网络与存储:overlay 网络和 persistent data 的实战选择
6.1 overlay 网络:跨主机的“魔法网线”
Swarm 模式下,最常用的网络类型是 overlay。创建方式:
docker network create -d overlay --attachable my-overlay--attachable允许独立的普通容器(非 service)也能挂到这个网络上,在调试和临时工具容器时非常有用。不加这个参数,普通的docker run --network my-overlay是跑不起来的,会报网络找不到。
Overlay 网络让不同机器上的容器互通 IP,就像它们在同一个局域网里。后端服务只需要通过服务名相互访问,比如 API 容器里连接数据库,直接写mysql:3306,不需要知道数据库跑在哪台机器上。这是 Swarm 内置 DNS 解析的功劳。
6.2 路由的注意点:对外端口别乱打
Overlay 网络内部通信没问题,对外访问则建议通过服务发布的端口来暴露。不要直接在容器里写死--network host,这样既破坏了 Swarm 的调度灵活性,又绕开了路由网格。我在生产环境里见过同事为了“省事”,把数据库服务的端口 3306 直接发布到所有节点,数据库的密码又是弱口令,这台机器没多久就被扫端口尝试暴力破解。对外只暴露必要端口,数据库这类服务建议只暴露给特定的 overlay 网络,不要走到不安全的网络区域。
6.3 持久化存储:有状态服务在 Swarm 里的三副手铐
无状态服务,比如 Nginx、API 后端,Swarm 管起来轻松。有状态服务,比如 MySQL、Redis、MongoDB,就需要认真考虑数据怎么存了。Swarm 提供三种持久化方案:
本地卷(Local Volume):数据存在某个节点的磁盘上,调度器把副本固定到该节点。优点是简单,缺点是数据只能活在那台机器上,节点挂了,数据就跟着物理隔离了。定义方式:
docker service create \ --name mysql \ --mount type=volume,source=mysql-data,target=/var/lib/mysql \ --constraint node.labels.type==ssd \ mysql:8NFS 共享存储:把多台机器共用一个网络文件系统,数据在集群里任何节点都能访问。方案是每个节点挂载同一个 NFS 目录,然后:
docker service create \ --name mysql \ --mount type=volume,source=nfs-data,target=/var/lib/mysql \ --mount type=bind,source=/mnt/nfs/mysql,target=/var/lib/mysql \ mysql:8注意:记不住 NFS 和 bind 的具体格式没关系,核心是 binding 了 NFS 的目标目录。NFS 方案适合中小规模,缺点是 NFS 本身也是单点,它的高可用需要再叠加一层方案。
专门的存储驱动,例如 Rook、Longhorn 之类,能为 Swarm 提供真正的分布式块存储和复制能力。但这类方案配置复杂度陡增,最完美的也不过是把 Kubernetes 的存储经验迁移回来。我的建议排序是:单机小型项目用本地卷加节点约束,多机数据可靠性要求高用 NFS,要求极高再到 Rook,别一上来就追求分布式存储的酷炫,复杂度真的能吞掉你的周末。
6.4 服务发现:Swarm 内置的“电话簿”
每个服务在创建时,Swarm 都会为它分配一个虚拟 IP(VIP),并自动注册到内置 DNS。其他容器只要在同一个 overlay 网络上,直接 ping 服务名就能解析到这个 VIP。VIP 背后对应着一组副本,Swarm 会自动把请求负载均衡到这组副本上。
举个例子,一个叫api的服务有 3 个副本,另一个worker服务的代码里访问http://api:8080,它会命中这 3 个副本中的某一个。这个过程由 Swarm 内建的 mesh routing 完成,不需要额外部署注册中心。如果你不喜欢 VIP 模式,可以在服务创建时加--endpoint-mode dnsrr,使用 DNS 轮询模式,服务名解析会返回多个地址,由客户端自己挑一个连接。大规模微服务场景可以用 dnsrr 减轻 VIP 的负载,但大多数项目用默认的 VIP 就够了。
7. 常见问题与排查技巧实录
7.1 节点显示 Down 了怎么办?
排查顺序永远是从外到内:
- 先看物理节点状态:ping 一下,能通则机器没挂。
- 再看 Docker 守护进程:
systemctl status docker。 - 看 agent 和 manager 之间的连通性:确认 2377 端口能通,
telnet <manager-ip> 2377。 - 查看节点状态:
docker node ls。如果节点一会儿 Ready 一会儿 Down,多半是网络抖动或者时钟不同步。对,时钟不同步这个坑极大。Swarm 依赖 Raft 选主,节点时间偏差太大会导致心跳超时,节点反复上下线。我在公司服务器上特地挂了一个 NTP 定时同步任务,从那之后节点 Down 的偶发问题基本消失。
7.2 服务创建成功但始终显示 Pending
docker service ps里如果显示New或Pending状态,通常是调度器找不到合适的节点放置这个副本。原因无外乎三个:
- 节点资源不足:
docker node inspect <node>查看可用内存和 CPU。 - 约束条件不匹配:比如约束了
node.labels.type==ssd,但所有节点都没打这个标签。 - 镜像拉取失败:在目标节点上手动
docker pull 镜像名测试一下,有些私有镜像仓库的凭证没在所有节点上配置,一旦副本被调度到没凭证的节点,状态就一直卡在 Pending。
7.3 路由网格访问间歇性失败
访问发布端口时,偶尔连接失败,大概率是 ingress 网络出问题。优先检查 4789 端口的 UDP 是否放行。路由网格的数据平面走 UDP 4789,很多云厂商安全组默认只放行 TCP,这端口一漏,数据面就乱。另外,查看 ingress 网络是否存在:
docker network inspect ingress如果这个网络处于异常状态,解决办法是先把所有服务停掉,然后重启 docker 守护进程,systemctl restart docker,最后重新创建服务。这不是一个优雅的方案,但在我实际经历里,它 90% 能救回来。
7.4 加入了集群但docker node ls看不到自己
这种情况绝大多数是join的 token 不对,或者 manager 节点在初始化后防火墙未放行 2377。还有一种可能是你用 manager token 加入但 manager 数量已经达到法定上限,加入命令返回成功但实际并没有正式注册。解决方法是重新拉取 token:
docker swarm join-token manager然后在目标节点重新执行 join。
7.5 服务更新回滚后,还留有旧副本怎么办?
我遇到最头疼的问题是滚动更新失败,回滚命令也执行了,但旧副本数量没恢复,总是在“New”和“Shutdown”之间反复横跳。后来发现是健康检查的 start-period 太长,更新的失败检测周期跨度过大,容器一直在被创建和杀掉。解决办法是把 start-period 调低到 5 到 10 秒,同时调低 retries 到 2,让失败判定快速收敛。
8. 进阶调优与生产化建议
8.1 将 Manager 节点“隔离”出来,不让业务容器占用控制面
生产环境里,用docker node update --availability drain把管理节点的可调度性设为 drain,让它不再接收业务副本。这样管理节点专门负责 Raft 协调和调度,性能稳定,核心控制面不受业务波动影响。注意docker node update --availability drain只能把该节点上的现有服务慢慢迁移走,如果你临时需要把一台机器变成全封闭状态,这个命令比直接踢出集群更体面。
8.2 用 Compose 文件和 Swarm 的 services 配套管理配置
写docker-compose.yml时,强烈建议把deploy.resources.limits控制好。一个常见误区是服务没设 CPU 内存上限,某副本内存泄漏把整台节点拖死,Swarm 调度器也被迫把新副本调度到其他节点,最终集群整体资源被拖垮。设限之后,Swarm 会强制杀掉超限副本并尝试重新调度,至少不会蔓延到整个节点:
deploy: resources: limits: cpus: "1.0" memory: 512M8.3 跨机房部署怎么办?
Swarm 是典型的单数据中心方案,跨机房场景会有网络延迟和分区问题,Raft 在这种网络下很容易抖动。我的建议是:跨机房用多个独立 Swarm 集群,上层加一层全局 DNS 或负载均衡器。别想着让一个 Swarm 集群横跨两个机房,除非你能忍受某个机房网络抖一下,整个集群调度全部瘫痪。
8.4 监控与告警:Swarm 集群必须有的“仪表盘”
Swarm 本身没有自带 Web 管理界面,也没有可视化监控面板。要想看到每个节点的资源占用、每个服务的运行状态,我用得顺手的组合是 cAdvisor 加 Prometheus 加 Grafana。cAdvisor 负责在每台节点上收集容器指标,Prometheus 负责抓取存储,Grafana 负责画图。整套部署同样用 Swarm 服务方式跑起来,把 Prometheus 和 Grafana 服务放在 overlay 网络上,用标签约束它们落在指定节点,调度问题也省心。
如果真的不想部署这么大一套,至少也要有docker events和docker service ps的定时巡检脚本。我最初的集群状态检查就是一段 5 行 Shell 脚本,每 2 分钟检查一次docker service ps是否有异常状态,一有问题立刻往群里发告警,这已经足够撑起小型项目了。
9. 我个人经验里 Swarm 最被低估的 3 个特性
先声明,我不是来吹 Swarm 的,它的短板实在明显:跨机房能力弱、持久化存储方案绕、大规模上千节点的场景远不如 Kubernetes。但在正向价值上,这三个特性我觉得不光是够用,而是“在某些场景下相当优秀”。
第一,多主机日志聚合。配合 Docker 的json-file日志驱动,或者更上一层用gelf驱动把日志发送到统一日志平台,Swarm 在多主机场景下不需要额外组件就能统一采集容器日志。每个服务实例产生的日志会自动聚合到日志平台,按服务名、节点名可以精确过滤。Kubernetes 即使功能再丰富,这个场景下也未必有什么显著优势。
第二,加密分布式集群状态。默认 Swarm 的整个集群管理通信和节点间数据面通信都是加密的,节点证书自动轮换,管理节点的敏感数据落盘也加密。如果不主动折腾证书体系,新装的 Swarm 集群开箱就是加密传输。我见过不少公司连 HTTPS 都没上齐,Swarm 这种默认安全的姿态挺省心的。
第三,服务滚动更新的可观测性。docker service ps输出里包含每个副本的当前状态、错误信息、更新历史,过度复杂的环境里排查问题真的快。你不必像在 Kubernetes 里那样翻多个组件日志才能拼出发生了什么,Swarm 会在一条命令里把所有生命周期告诉你。
10. 写在最后:我的建议与一点执念
摸索容器编排那段时间,我总被问“为什么不用 Kubernetes,Swarm 不是都没人用了吗?”我向来不迷信热度,只在乎项目管理成本、维护成本和能不能解决问题。中小规模的业务系统、公司内部工具、自建服务这些场景,用 Swarm 完全没有问题,团队里只要会 Docker 命令的人,基本上一两个小时就能上手,比我当时从零摸 Kubernetes 花了两周的时间强太多。
但我也有个执念:生产环境里再简单的技术也要按生产标准去对待。即便用了 Swarm,你依然要给服务设置资源限制、校验健康检查、规划持久化存储、做好监控告警。容器编排不是终点,它只是帮你把“部署机器、拉镜像、起容器、观察状态、处理故障”这些重复劳动自动化的一层工具。工具可以选简单的那一个,但工程纪律不能因为工具简单就省掉。
如果你读到这里,正准备去搭第一个 Swarm 集群,我的建议是:直接用三台虚拟机,部署一个有状态服务和一个无状态服务,配上健康检查和滚动更新,亲手把节点下线再上线,看它怎么自动恢复。这个过程之后,你会对“编排”这两个字有真实的身体记忆。踩过几个坑,才能真正理解为什么管理者要操心节点数量、端口和调度策略,也才能在工作中用自己的判断力选择适合的工具,而不是被热度推着走。