ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Docker Swarm的Mode全面解析:从集群初始化到滚动更新

2026/10/2 20:19:26 拓冰建站 浏览量
Docker Swarm的Mode全面解析:从集群初始化到滚动更新 聊到 Docker Swarm很多人第一个想到的是docker swarm init那行命令敲完就觉得集群起来了。但真正把 Swarm 用在生产环境之后你会发现有个词贯穿始终那就是 Mode。集群怎么组、服务怎么调度、更新怎么推进、故障怎么切换背后全是 Mode 在起作用。这篇是 Docker Swarm 架构拆解系列的第一篇先把这个最基础也最容易被忽略的概念彻底讲透。这个系列面向的是准备把 Swarm 用于实际业务的开发、运维和架构师也适合刚接触容器编排、想搞清楚 Swarm 和单机 Docker 到底差在哪的人。读完你不仅能分清 Swarm Mode、Service Mode、Update Mode 这些术语还能直接在命令行里完成集群初始化、服务部署和更新回滚的完整流程。我尽量把参数背后的原因也讲清楚而不是只给一个“能跑就行”的配置。1. Mode 到底指什么先看清 Swarm 的三种“模式”1.1 集群模式把多台机器变成一台逻辑主机Mode 在 Docker 世界里最先指的就是 Swarm Mode也就是 Docker Engine 的集群运行模式。默认情况下Docker 以单机模式运行你敲docker run、docker ps操作的都是本机容器所有资源只属于当前这台机器。而开启 Swarm Mode 之后多台机器的 Docker 守护进程会组成一个集群容器调度、网络互通、配置分发都由集群统一管理对外看起来就像一台更大的“逻辑主机”。这个转换不是靠安装额外组件实现的而是 Docker Engine 自带的集群能力。你只需要在某一台机器上执行docker swarm init当前节点就会成为管理节点Manager Node然后生成一串 join token其他机器拿着 token 执行docker swarm join就能加入集群。整个过程不需要单独部署 etcd 或者 Consul因为 Swarm 内置了 Raft 共识算法来维护集群状态。判断当前机器是否处于 Swarm Mode最直接的方式是执行docker info看输出的Swarm字段。如果显示active说明这台机器的 Docker 守护进程已经运行在集群模式下如果显示inactive则是普通的单机模式。我见过不少同事在排查问题时先跑docker node ls然后报错说找不到节点最后发现根因是这台机器压根没启用 Swarm Mode。提示Swarm Mode 不是独立于 Docker Engine 的进程它是引擎的一种运行状态。同一套 Docker 命令在单机模式和集群模式下行为会不一样尤其是网络、存储和负载均衡相关的操作。1.2 服务模式定义副本跑在哪、跑多少集群搭好之后你不再用docker run直接启动容器而是通过docker service create创建服务。服务Service是 Swarm 里的调度单元它定义了容器镜像、环境变量、端口映射以及最重要的——任务调度模式Deployment Mode。这里 Mode 的第二个含义就出现了服务是以副本模式replicated还是全局模式global运行。副本模式是默认值你在命令里指定--replicas 3Swarm 就会在集群里挑选三台空闲节点各跑一个任务副本。指定--replicas 5就五个副本Swarm 负责保证任何时刻集群里正好有五个副本在运行。全局模式则完全不同它不关心副本数量而是保证集群里每一台满足条件的节点上都运行一个任务。你创建一个 global 服务Swarm 会自动在所有节点上部署后续新节点加入集群时这个服务也会自动在该新节点上启动。这两种模式的选择直接影响服务的伸缩性、资源分布和故障恢复行为。比如日志采集器、监控探针这类“每台机器都应该有一个”的组件天然适合 global 模式而业务 API、数据库这类按流量伸缩的组件则应该用 replicated 模式来控制副本数。1.3 更新模式发布新版本时如何替换任务Mode 的第三个应用场景是服务更新。当你要把镜像从 v1 升级到 v2 时docker service update会按一定的策略替换正在运行的任务这套策略就是更新模式Update Mode。Swarm 支持滚动更新rolling update你可以控制每次同时替换几个任务--update-parallelism以及每批替换之间的间隔时间--update-delay。更新模式是生产环境里最容易出事的地方。很多人第一次做滚动更新把 parallelism 设成 10delay 设成 0结果一瞬间所有旧版本容器都被拉起来的新版本替换如果新镜像有问题整个服务直接不可用。后面我会用实际命令演示如何配置更新模式以及如何设置失败自动回滚。2. 从零进入 Swarm Mode初始化与节点接入实操2.1 初始化管理节点并理解端口与地址参数我一般在一台干净的 Linux 服务器上开始搭建 Swarm 集群Ubuntu 22.04 搭配 Docker Engine 24.x 是我用得比较稳的组合。初始化命令非常简单docker swarm init --advertise-addr 192.168.1.10 --listen-addr 192.168.1.10:2377--advertise-addr是告诉集群里的其他节点要连接我这个管理节点请访问这个 IP 地址。如果机器有多块网卡这个参数特别关键不指定的话 Docker 会自动检测但自动检测经常选错网卡导致其他节点无法加入。比如机器上同时有内网 IP 192.168.1.10 和公网 IP 203.0.113.5如果你的集群只在内网通信就明确写成内网 IP否则节点 join 时会被拒。--listen-addr是当前节点监听集群通信的地址和端口默认是 0.0.0.0:2377。2377 是 Swarm 集群管理通信的专用端口用于节点间的心跳、Raft 日志同步和领导选举。如果你启用了防火墙务必放通 TCP 2377另外还要放通 UDP 7946节点间 gossip 协议和 TCP/UDP 4789VXLAN 数据面通信。我踩过最典型的坑就是只放了 2377节点能加入集群但 overlay 网络里的容器互相 ping 不通折腾半天才发现是 4789 被防火墙拦了。执行完初始化之后命令行会输出两段 join token一个是管理节点的一个是工作节点的。注意保存好后面扩展集群全靠它。2.2 工作节点接入与节点角色验证工作节点的接入命令更简单在另一台机器上执行docker swarm join --token SWMTKN-1-xxxxx 192.168.1.10:2377其中SWMTKN-1-xxxxx就是初始化时输出的 worker token。加入成功之后回到管理节点执行docker node ls你会看到类似下面的输出ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION abcdef123456 node01 Ready Active Leader 24.0.7 ghijkl789012 node02 Ready Active Reachable 24.0.7 mnopqr345678 node03 Ready Active 24.0.7MANAGER STATUS列显示 Leader 或 Reachable 的节点就是管理节点工作节点这里为空。AVAILABILITY列显示 Active 表示节点正常接收任务分配Drain 表示排空状态、不再接收新任务但保留已有任务。生产环境维护节点时把节点切到 Drain 是所有运维都应该养成的好习惯。我平时验证集群是否健康会依次跑三个命令docker node ls看节点状态、docker service ls看服务状态、docker network ls看网络是否正常。任何一个环节异常都能快速定位是大方向的问题。2.3 节点退出与集群重置的常用操作节点要退出集群用docker swarm leave。工作节点执行docker swarm leave之后管理节点上还要执行docker node rm node-id把节点记录彻底删掉。注意顺序很重要如果节点已经失联docker node rm可能会报错需要加上--force。管理节点退出不能用简单的 leave因为管理节点退出会导致集群可用性下降尤其是只剩一个管理节点时直接 leave 它等同于解散集群。正确做法是先docker node demote node-id把它降级为工作节点再让它 leave。如果你想把整个集群推倒重来在每台节点上执行docker swarm leave --force然后把/var/lib/docker/swarm目录清掉通常重置 Docker 环境时会用到最后重新 init 就行。这个操作会丢失集群所有状态包括服务定义和加密密钥不是特殊情况不要碰。2.4 初始化时容易忽略的高可用配置初始化单节点 Swarm 也能跑但如果你准备部署生产业务我强烈建议至少准备三台管理节点。原因在于 Swarm 用 Raft 协议管理集群状态管理节点之间需要达成多数派共识quorum才能对外提供服务。三台管理节点的多数派是 2 台两台宕机之后集群仍然能正常调度如果只有 1 台管理节点这台宕机整个集群控制面就瘫痪了虽然运行中的服务不会立刻停止但你无法发布新服务、无法扩缩容、无法更新配置。管理节点数量建议保持奇数2 台和 4 台都不合适。4 台管理节点和 3 台管理节点的容错能力完全一样都最多只能挂 1 台但 4 台意味着每次共识需要更多节点参与性能和复杂度都更高。这个原则跟 etcd、ZooKeeper 集群的选型逻辑是一样的。我实际搭建三节点集群时的顺序是node01 上docker swarm initnode02 和 node03 都加入为管理节点join 时使用 manager token然后验证docker node ls里有三台 MANAGER STATUS 非空的节点。整个过程不超过两分钟但换来的高可用等级完全不同。3. 部署模式二选一replicated 与 global 的架构取舍3.1 两种调度模式的运行逻辑差异创建服务时的--mode参数决定了调度器如何分发任务。默认是replicated调度器根据你指定的副本数量在集群内寻找合适的节点放置任务。它会综合考虑节点资源、节点标签、端口占用等因素。而global模式忽略副本数量调度器会在每一台 AVAILABILITY 为 Active 的节点上都放置一个任务新节点加入集群时会自动补上节点被 Drain 或离开集群时自动移除。我用生活中的例子来解释replicated 模式就像外卖平台派单你点了 3 份订单调度后台分给 3 家店铺各自做 1 份具体分给哪家店铺取决于哪家空闲、哪家配送范围合适global 模式则像小区里的垃圾桶不管小区大小每一栋楼楼下都必须放一个新楼盖起来自动补上楼拆除后垃圾箱也跟着撤走。这个差异在故障恢复场景下的行为也不同。replicated 服务某节点宕机后Swarm 会在其他健康节点上重新调度一个副本维持总副本数不变global 服务某节点宕机后Swarm 不会在其他节点上新增任务因为 global 保证的是“每一台节点一个任务”这台节点没了任务自然就没了等节点恢复后任务会自动回来。3.2 创建与验证 replicated 和 global 服务下面我在一个三节点集群里分别创建两种模式的服务让大家直观感受区别# 创建 3 副本的 Nginx 服务模式为 replicated默认 docker service create --name web-rep --replicas 3 --publish published8080,target80 nginx:1.24-alpine # 创建全局模式的 Nginx 服务 docker service create --name web-global --mode global --publish published8081,target80 nginx:1.24-alpine然后查看任务分布docker service ps web-rep输出里你会看到三个任务分散在不同节点上NAMES 列类似web-rep.1.xxxxx、web-rep.2.xxxxx、web-rep.3.xxxxx。再看全局服务docker service ps web-global输出里同样有三个任务但分别落在三台节点上而且是每台节点各一个。如果你之后又加入第四台节点不需要任何手动操作Swarm 会自动在第四台上启动一个 web-global 任务。这是 global 模式最有用的特性。3.3 生产环境选型建议监控采集用 global业务应用用 replicated我常用的选型原则可以用一句大白话概括凡是你希望“每台机器都有那么一个”的东西用 global凡是需要按流量伸缩、精细控制数量的东西用 replicated。最典型的 global 应用是监控采集器。比如部署 Prometheus 的 node-exporter你期望每一台 Swarm 节点上都跑一个实例采集主机指标节点扩容后监控自动覆盖新机器节点下线后采集任务自动消失。用 global 模式整个集群的监控覆盖不需要任何手动干预。再比如日志采集 agent类似 Filebeat 或 fluentd也是每台节点都得有的组件同样适合 global。replicated 模式则适用于所有无状态业务服务比如 Web 前端、API 网关、消息消费者。它们需要根据业务流量灵活调整副本数用docker service scale命令就能热伸缩。特别注意一点有状态服务比如 MySQL虽然通常也用 replicated但不能随便 scale 到多副本因为数据一致性不是 Swarm 帮你解决的。我在实际项目中直接用 Swarm 跑 MySQL 的场景很少一般只用 single-replica 的方式把 MySQL 作为服务托管起来真正的多副本和高可用交给数据库层方案比如主从复制、半同步复制去处理。还有一种针对有状态服务更优的调度方式是把服务约束到指定节点上配合 volume 使用。比如给数据库节点打标签node.roledb然后创建服务时加上约束条件Swarm 只会把任务调度到这些节点上。这样做的好处是数据盘可以保持固定不用担心任务漂移到其他节点后数据目录对不上。对比维度replicated 模式global 模式副本数量由 --replicas 指定每台节点固定一个扩缩容手动 scale 或自动更新随节点数量变化适用场景业务接口、有状态服务、按流量伸缩的服务监控采集、日志采集、网络代理故障恢复在健康节点重新调度副本节点恢复后任务自动恢复调度控制精细可配合约束和资源预留简单遍布全集群注意global 服务配合端口发布时要小心。如果你在每台节点上都有任务端口发布又是 Swarm 的 ingress 模式会出现所有节点都监听同一发布端口的情况。比如上面创建的 web-global 发布 8081 端口你访问任意一台节点 IP 的 8081 端口都能命中服务这在某些安全审计场景下可能不是你想要的。4. 更新模式与故障切换生产环境最关心的一课4.1 滚动更新的参数怎么定parallelism、delay 与 failure-action当你发布新镜像时docker service update的默认行为是逐个替换任务先停止一个旧任务、启动一个新任务等新任务运行成功后再继续替换下一个。这种滚动更新的模式可以用--update-parallelism控制并发数用--update-delay控制每批之间的间隔。我建议的参数策略是这样的先小步快跑再平稳扩大。第一次发布parallelism 设为 1delay 设成 30s观察一两个任务跑起来没问题再手动把 parallelism 调大。更新命令本身也可以重复执行不会产生冲突docker service update \ --image nginx:1.26-alpine \ --update-parallelism 1 \ --update-delay 30s \ --update-failure-action pause \ web-rep--update-failure-action有两个可选值pause和continue。生产环境务必设置为pause因为一旦新任务启动失败Swarm 会暂停整个更新流程给你留出排查时间。如果用默认的continueSwarm 会继续尝试替换剩余任务新版本有 bug 时整个服务的所有副本都会被污染后果非常被动。--update-order参数也值得留意默认是stop-first也就是先停旧任务再启新任务。对于无状态服务这没问题但对有状态服务停旧和启新之间会有一段空窗期服务不可用。另一个选项是start-first先启动新任务并确认健康后再停旧任务这样能最大程度减少中断但需要额外的网络端口或资源来同时运行新旧两套任务。我的习惯是流量高峰期的核心服务用start-first普通内部服务用stop-first。4.2 失败自动回滚给自己的发布上一道保险光有 pause 还不够Swarm 还支持自动回滚。你在更新服务时同时指定--rollback-parallelism和--rollback-monitorSwarm 会在新任务运行状态异常时自动把服务回滚到上一个版本。docker service update \ --image myapp:2.0.0 \ --update-failure-action rollback \ web-rep--update-failure-action设置为rollback之后如果任务启动失败或者健康检查失败Swarm 会自动执行回滚把镜像恢复为之前的版本。这里有几个细节要注意健康检查HEALTHCHECK的判定直接决定回滚是否触发如果你没有给镜像定义健康检查Swarm 只能靠进程退出码判断失败很多“启动了但业务异常”的情况不会被识别。所以在制作业务镜像时一定要在 Dockerfile 里加上合适的 HEALTHCHECK 指令比如检查某个 HTTP 接口是否能返回 200。我自己有过一次印象深刻的教训更新镜像后所有容器的进程都正常启动端口也监听了但因为依赖的配置中心连接失败接口一直返回 503。由于镜像没有健康检查Swarm 认为任务运行正常更新照常进行等到我手动发现业务异常时所有副本都已经切换到新版本了。那次之后我要求团队所有业务镜像必须包含健康检查才允许发布到 Swarm 集群。4.3 高可用模式的底层Raft 共识与 Leader 选举Swarm 的高可用靠的是管理节点组成的 Raft 集群。每个管理节点都维护一份集群状态的日志包括服务定义、任务状态、节点列表等。当管理节点收到变更指令时Raft 协议会要求多数派节点确认写入只有超过半数的节点都记录了这条变更才真正生效。这套机制保证了不会出现两个管理节点各自为政、状态分叉的情况。Leader 选举是 Raft 的核心行为。当 Leader 节点异常失联后其他管理节点会发起新一轮选举选出新的 Leader选举期间集群不接受新的变更操作。这个过程通常很快但对正在执行的服务更新、扩容操作会有短暂阻塞。生产环境的管理节点如果频繁重启会不断触发选举影响控制面的稳定性。我见过有团队把五个管理节点部署在同一台物理机上的不同虚拟机里结果物理机断电后集群完全瘫痪所谓的高可用形同虚设。管理节点要分布在不同的故障域里至少分散到不同的物理机或者不同的机架否则 Raft 的容错设计发挥不出作用。需要临时降级某个管理节点时执行docker node demote node-id docker node promote node-idpromote 和 demote 可以动态调整节点角色不需要重启服务。4.4 重启策略容器崩溃时 Swarm 如何响应服务还有一个经常被忽略的 Mode——Restart Policy重启策略。docker service create可以通过--restart-condition设置容器退出后的行为可选值包括none、on-failure和any默认是any。也就是说无论容器是以正常退出码0还是异常退出码非 0结束Swarm 都会重新拉起任务。这个策略跟 Docker 单机模式的--restart参数类似但行为上有区别单机模式的 restart 是 Docker 守护进程管理容器生命周期Swarm 的重启则是调度器重新创建任务。我遇到过一个诡异的问题一个批处理任务设计好了跑完就退出结果在 Swarm 里创建的服务反复重启日志里全是重复执行记录。原因就是默认的 restart policy 是any批处理跑完退出码为 0Swarm 认为任务异常结束又把它拉起来了。解决方法是创建服务时显式指定docker service create --restart-condition none --name batch-job busybox echo done反过来如果你希望服务一直在线即使进程正常退出也要拉起来那就用默认的any或显式写--restart-condition any。判断一个服务到底适合哪种重启策略关键看它是长驻型进程Web 服务、队列消费者还是短生命周期任务批处理、一次性脚本这个决策在创建服务时就应该想清楚而不是等出问题时再补。5. 网络模式与实测排坑从端口到 DNS 的全链路梳理5.1 Swarm 内置的 overlay 与 ingress 网络创建 Swarm 集群后你会发现docker network ls多出几个网络。ingress是 Swarm 内置的入口网络负责对外发布端口的流量路由。docker_gwbridge是节点上的桥接网络用于容器访问外部网络。还有一个docker_gwbridge通常是自动创建的不需要手动维护。当你在服务上发布端口时比如--publish published8080,target80Swarm 会在 ingress 网络上创建一个 VIP虚拟 IP所有节点的 8080 端口流量都被接入这个 VIP再由 Swarm 内部的负载均衡转发到具体的任务副本。这就是 Swarm 的服务发现和负载均衡机制客户端访问任意节点的任意发布端口都能到达服务无需额外部署反向代理。覆盖网络overlay network用于服务间通信。创建一个自定义 overlay 网络并让两个服务都接入它们之间就可以通过服务名直接互通docker network create -d overlay --attachable my-overlay docker service create --name app --network my-overlay nginx:1.24-alpine docker service create --name db --network my-overlay mysql:8.0在 app 容器里你可以直接访问主机名dbSwarm 内置的 DNS 会解析到 db 服务的 VIP。--attachable参数允许普通容器非 Swarm 服务也连接到这个 overlay 网络这在调试时特别有用。我把一个 debug 容器挂到 overlay 网络上直接 ping 服务名验证网络连通性比登录到服务容器里操作安全得多。5.2 跨节点通信频繁失败指向 VXLAN 与防火墙Swarm 的 overlay 网络基于 VXLAN 技术数据包在节点之间通过 UDP 4789 封装传输。跨节点通信出现间歇性失败十次里有八次是 UDP 4789 被防火墙丢弃还有两次是 MTU 不一致。我遇到过最隐蔽的一次集群节点分别位于两个机房A 机房的网络设备支持 1500 MTUB 机房的核心交换机 MTU 设置成了 1400。VXLAN 封装后的数据包比原始数据包大 50 字节左右超过 MTU 就直接丢包。表现症状非常奇怪同一 overlay 网络里的两个服务在 A 机房内部通信正常在 B 机房内部也正常A 和 B 之间通信时断时续。后来在管理节点上把 overlay 网络的 MTU 调整成 1350 才彻底解决。调整网络 MTU 的方法docker network create -d overlay \ --opt encapipv4 \ --opt mtu1350 \ my-overlay这个参数只在创建网络时生效已经创建的网络改不了需要重新创建再让服务切换。如果你只是临时验证可以先用--attachable创建一个测试网络挂到服务上看效果确认无误后再切正式网络。5.3 虚拟化环境常见问题Docker Desktop 与 WSL2 的影响本地开发时很多人用 Docker Desktop 跑 Swarm 集群。Docker Desktop 在 Windows 和 macOS 上依赖虚拟化技术启动失败最常见的报错是 “virtualization support was not detected” 或者 “failed to start because virtualisation support wasnt detected”。这个问题通常是 Windows 的 Hyper-V 或 WSL2 功能没有启用导致的。解决办法是先到“启用或关闭 Windows 功能”里勾选“适用于 Linux 的 Windows 子系统”和“虚拟机平台”然后重启系统再启动 Docker Desktop。如果你用 Docker Desktop 跑多节点 Swarm还有一个更快的办法Docker Desktop 自带 Kubernetes但 Swarm 的支持相对有限本地模拟集群最佳方案还是用 Vagrant 或者 Multipass 拉起多台 Ubuntu 虚拟机。我在 MacBook 上常用的方式是用 Multipass 创建三台 2C4G 的 Ubuntu 虚拟机然后在每台虚拟机上安装 Docker Engine再组成三节点 Swarm。本地实测和线上行为一致不需要忍受 Docker Desktop 在 Mac 上偶发的网络性能问题。5.4 排查 Mode 相关问题的命令速查日常维护 Swarm我建议把下面几个命令背下来排查效率会大幅提升# 查看节点状态、角色和可用性 docker node ls # 查看服务任务在所有节点上的分布和状态 docker service ps service-name # 查看服务配置、更新策略、网络端口等细节 docker service inspect --pretty service-name # 查看服务日志需要服务创建时指定日志驱动 docker service logs service-name # 查看特定任务所在节点和运行状态 docker inspect --format {{.NodeID}} container-id现象可能原因处理手段docker node ls显示 Down节点网络中断或 Docker 服务停止检查节点 2377 端口连通性重启 Docker 服务服务一直显示 Pending资源不足或约束不满足docker service ps查看错误信息检查节点资源跨节点容器 ping 不通overlay 网络异常或防火墙拦截检查 4789/7946 端口必要时重建网络更新任务一直卡在启动中镜像拉取缓慢或健康检查未通过docker service ps看 CurrentState查镜像源或日志管理节点无 LeaderRaft 共识失联检查管理节点间 2377 连通性和时钟同步滚动更新自动暂停update-failure-action设计为 pause查看失败任务日志修复后docker service update --update-failure-action continue有一个细节排查任务状态时docker service ps输出的 CurrentState 会记录任务从创建到当前的所有状态转换比如Assigned、Starting、Running、Failed、Shutdown。判断一个任务是否经历过重启看它对应行的 Replica 编号和上次状态如果同一个编号下有多个Failed记录基本能断定是镜像问题或启动命令问题而不是调度问题。写在最后一次多模式共存的实践体会我在实际项目里把三种 Mode 的配合用得很频繁Swarm Mode 负责集群生命周期replicated 模式承载无状态业务global 模式托管监控和日志采集更新模式控制发布节奏。一开始总是把注意力放在镜像和容器本身觉得 Mode 只是命令参数后来才发现Mode 才是决定整个集群行为方式的主线。比如同样一个 Nginx 服务用 replicated 跑 3 副本和用 global 跑出来的运维方式完全不同前者要管理扩缩容后者要管理节点生命周期。最后分享一个小技巧凡是遇到 Swarm 行为不符合预期先别急着翻日志先回答三个问题——当前集群处于什么 Mode服务是 replicated 还是 global发布时设置的更新策略是什么把这三个问题理清楚90% 的问题都能定位到方向。这个系列后续我还会继续拆 Swarm 的服务发现、存储卷、安全加密和 Ingress 流量治理Mode 这块的内容是地基地基稳了上面的架构才能站得牢。