☰
Docker Swarm Mode深度解析:replicated与global模式选型与实战
2026/10/8 2:48:32 网站建设 项目流程

Docker Swarm 这个题我念叨过很多次,但一直没系统写。这回决定开个系列,第一篇就挑最容易被忽略、却又最影响服务运行形态的参数:Mode。很多朋友刚接触 Swarm 时,会在教程里看到docker service create --mode replicated或者--mode global,但教程往往只给命令不给理由。我刚开始用的时候也踩过几次坑,所以这一讲我想把这个 Mode 彻底讲透:它到底是什么、两个选项各自解决什么问题、生产环境里怎么选、以及配置之后有哪些容易出幺蛾子的细节。

如果你已经在用 Docker 但还没上手 Swarm,或者你刚把服务从单机容器搬到集群编排,这篇对你应该很有参考价值。我会尽量用实际场景说话,把我在线上环境踩过的坑一并拿出来。

1. 为什么系列第一讲要聊 Mode:它决定了你的服务在集群里的"存在形态"

先说结论:Swarm 里 Mode 就两个值,replicated和global,但它定义的不是"启动几个副本"这么简单,而是整个集群调度系统对待你的服务的基本策略。

我用一个生活例子帮大家建立直觉。replicated模式就像开连锁店——你决定在某座城市开三家分店,具体开在哪个位置,由运营团队根据人流量、租金来安排。而global模式更像地铁站里的自动扶梯——每座车站都必须装一扶梯,不管这个站是小是大、客流多不多,反正标准配置,一个站一台。

对应到容器编排里:

  • replicated:你在创建服务时指定--replicas 3,Swarm 的调度器会从整个集群的工作节点里挑出合适的节点,让这个服务在这几个节点上一共运行 3 个任务(Task)。节点池里有 10 台机器,不要求每台都跑这个容器,只需要保证总副本数达到 3 即可。
  • global:你创建服务时说"凡是集群里的节点,每台都必须跑一个这个容器"。这时候--replicas参数基本失效,因为副本数直接等于集群里符合约束条件的节点数。集群节点多变动,副本数跟着自动变动。

这两种模式在docker service ls里看没有任何区别,但你把docker service ps展开,差距就出来了。replicated模式下任务分布是"点状"的,有的节点上有,有的节点上没有;global模式下任务分布是"面状"的,只要节点在线,每个节点都有对应任务。

很多初学者最容易忽略的一点是:这个 Mode 参数不是给单机 Docker 准备的。docker run时你不需要考虑 Mode,因为单机不存在集群调度问题。它是docker service create和docker stack deploy独有的概念。所以你如果还在单机容器阶段,会觉得这个概念陌生,这很正常,它属于"从单机走向集群"这个阶段才用得上的东西。

一句话总结我这边的理解:Mode 是 Swarm 集群对服务下发任务时的顶层策略开关,它比副本数更优先——先确定了"按总数调度"还是"按节点铺开",然后才轮到具体调度逻辑去计算任务落点。这也是为什么我把这个系列第一讲留给了它。

2. 两种 Mode 的底层区别:副本量到底是谁说了算

2.1 replicated mode 的调度规则和副本伸缩

我们来看一个实际场景。初始化一个三节点的 Swarm 集群,一个 ManagerLeader,两个 Worker,然后创建一个 replicated 服务:

docker service create \ --name web-demo \ --mode replicated \ --replicas 3 \ --publish 8080:80 \ nginx:1.27-alpine

你指定了 3 个副本,Scaling,它会在三个节点上各调度一个任务(因为副本数正好等于节点数)。这时候用docker service ps web-demo看分布,大概率是三台节点各一个任务。

如果这时候我把副本数改成 5:

docker service update --replicas 5 web-demo

Swarm 调度器会重新做一次"挑选",可能某些节点被分配了两个任务,另一些节点任务数为零。分配逻辑不是随机瞎选的,而是由 Swarm 的调度策略决定,默认情况下更倾向于把新任务调度到资源占用率更低的节点上,尽量保持集群负载均衡。

这里要提醒大家:replicated 的副本数是你和调度器之间的一个"协商结果"。你是甲方,说你想要 5 个副本;但调度器是乙方,它会根据节点资源、约束条件、端口冲突等实际情况来"尽量满足"。比如节点剩余内存不足,副本就起不来;再比如某个节点上有端口占用的容器,调度器会主动避开这个节点。所以 replication 模式比较适合那种无状态、可以水平扩展的业务,副本多一点少一点问题都不大。

2.2 global mode 的"节点全覆盖"逻辑

再看 global 模式。还是三节点的 Swarm,创建一个全局服务:

docker service create \ --name node-agent \ --mode global \ --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \ docker-agent:latest

这个服务一旦创建,集群里每一个节点上都会出现一个名为node-agent的任务。它是"全量覆盖"的,不需要你手动指定副本数,因为副本数的公式是:副本数 = 满足约束条件的节点数。

这里有三个隐藏细节值得注意:

第一,Manager 节点也会被调度 global 任务。默认情况下,Manager 节点实际上是参与服务调度的,不像 Kubernetes 那样默认不调度业务负载到控制平面节点。如果你不想让某个 global 服务跑在 Manager 上,必须显式加一个约束条件,比如--constraint node.role!=manager。不加约束的话,Manager 节点上一定会有这个 global 任务的副本。

第二,约束条件会直接影响副本总数。假设集群有 5 个节点,但你的 global 服务加了--constraint node.labels.arch==x86_64,实际只有 3 个节点带这个标签,那么运行的副本就是 3 个,其余 2 个节点不会跑这个服务。这一点很多人理解成"global 就是所有节点必须跑",不准确,准确说是"所有满足条件的节点必须跑"。

第三,新增节点时 global 服务会自动扩容。比如你在集群里加了一台新机器,那么已有的 global 服务会自动在这台机器上拉起对应的任务,这个过程不用你做任何操作。反过来,如果移除一个节点,这个节点上的 global 任务也没了,其他节点不受影响。这种自动伸缩特性在日志采集、监控上报、节点巡检这类场景里尤其有用,因为你不需要在扩容后手动补一个副本,它自己就知道往新节点上放。

我把两种模式的关键差异做了个对照表,方便快速查阅:

对比项replicated modeglobal mode
副本数量用户通过--replicas指定等于满足约束条件的节点数
新增节点副本数不变,需手动扩缩容自动在新节点上创建任务
移除节点任务随节点消失,副本数减少,调度器会同其他节点补副本对应节点上的任务消失,其他节点不补偿
适用负载无状态 Web、可水平扩展业务节点级守护、监控采集、日志代理
典型命令--mode replicated --replicas 3--mode global

2.3 调度器的"尽力而为"本质

理解了上面两者的差异,我想再补一个重要的底层认知:Swarm 调度器本质上也是"尽力而为"的。它不像 Kubernetes 那样有完善的 Pod 驱逐、调度器抢占机制,很多约束只是局部最优的尝试。

举一个真实例子。有一次我在一个 5 节点的 Swarm 集群里创建了一个 replicated 服务,副本数设置成 2。按理说它会把两个任务分散到不同节点上,但因为两台节点都打上了node.labels.zone==db这样一个只有 2 台节点有的标签,而我的服务约束是node.labels.zone==db,那么 2 个副本自然就分布在 2 台节点上,看起来没问题。但我原本的意图是"数据库实例要跨机架容灾",结果两个副本的物理机在同一机架上,因为我没有在约束里加上"机架"这一层标签。

所以大家一定要记住:Mode 只是定义"总量逻辑"和"节点全覆盖逻辑",具体任务落在哪台节点,得靠约束条件(constraints)和调度策略(placement preferences)来进一步细化。Mode 解决"有几个"的问题,约束解决"在哪几个"的问题,这两者是配合使用的关系。

3. 选型决策:什么场景该用 global,什么场景该用 replicated

3.1 多数业务服务:老老实实用 replicated

我见过不少朋友一上来就喜欢给所有服务都加--mode global,觉得这样可以"每台机器都跑一份,负载均衡天然搞定"。对于无状态 API 服务来说,这个思路是错的。

举个例子。你有一个 nginx 服务,用户量上来之后你需要 10 个实例扛流量。如果走 global 模式,副本数完全被节点数绑架——集群有 7 台节点,你就只能跑 7 份,多了没有;集群扩容到 20 台,副本数直接变成 20,可能远超你的负载需求,白白浪费资源。而replicated模式下,你随时可以通过docker service scale web=10精确控制实例数量,要 10 个就 10 个,要 15 个就 15 个。这才是"服务编排"应该有的样子。

另外在滚动更新(rolling update)方面,replicated 模式也更灵活。Swarm 默认的更新策略是分批替换,比如先停掉一个旧任务,等新任务起来且健康检查通过,再停下一个。你可以通过--update-parallelism 2 --update-delay 10s这类参数控制每批更新的数量和间隔。global 模式虽然有同样的更新参数,但因为副本数等同事节点数,大批量更新时可能造成所有节点在同一窗口期陆续重启,对服务整体的稳定影响面更大。

3.2 监控采集与日志代理:global 是天然答案

如果是节点级别的 Agent 类服务,基本就是 global 模式的"标准用户"。比如:

  • 每台节点都要跑一个日志采集器,把/var/lib/docker/containers/*.log收走;
  • 每台节点都要跑一个监控指标采集器,把 node exporter 上报到 Prometheus;
  • 每台节点都要跑一个定时安全扫描组件,检查镜像漏洞和可疑进程。

这些服务有一个共同特点:它们的"服务对象"是节点本身,而不是某个业务端口。你用 replicated 模式的话,会面临一个尴尬问题:新加一台节点,忘了扩一个副本,新节点就裸奔在监控视野之外。用 global 模式则可以保证"只要节点在集群里,它一定被采集到"。

我自己维护的一套 Swarm 环境里,Prometheus 的 node-exporter 就是用 global 模式部署的。每次我需要扩容一台计算节点,只要把这台节点docker swarm join进集群,Prometheus 自动就能抓到新的 target,不需要我手动在 Compose 里改副本数,也不用更新 Prometheus 配置文件。这种"新节点自动接入监控"的体验,用过一次就不想回去了。

3.3 有状态服务:两种模式都要谨慎

有状态服务的选型比无状态要复杂一点。如果业务强依赖数据分片,且每个分片恰好部署在一个节点上,那么 global 模式可以作为一种投机取巧的方案。比如你用 Cassandra 或 ClickHouse 做分布式存储,希望在每台节点上都跑一个实例,再通过集群内部复制实现数据冗余,那 global 模式挺合适。

但这有个大坑:有状态服务通常需要在节点故障时把数据迁到别的节点上重新拉起。global 模式在节点宕机后不会在其他节点"补开"一个新实例,因为其他节点上已经有了各自的任务。这意味着该节点上的数据分片会一直处于缺失状态,直到你手动介入或节点恢复。如果你用的是 replicated 模式,调度器反而会因为某个副本挂了而在其他节点重新拉一个副本出来(前提是数据来自共享存储或者可以远端同步)。

所以我个人对有状态服务上的建议是:

  • 如果数据必须和节点磁盘绑定(比如本机 Volume 存储),请谨慎使用 global;
  • 如果数据来自分布式存储或外部数据库,且希望故障后能在别的节点快速拉起新副本,用 replicated 更稳;
  • 如果是"每个节点本地缓存"类服务,比如跨节点的本地代理、本地 DNS 缓存,global 反而更合理,故障了继续等节点恢复就行,不需要"补副本"。

3.4 附加决策维度:成本、安全与运维习惯

除了服务类型本身,选 Mode 时还要考虑成本和运维习惯。

成本方面,global 模式副本数随节点数水涨船高。如果你有 50 台节点,跑一个 global 的服务就等于同时起 50 个容器,即便每个容器只占 128MB 内存,也是 6.4GB 的开销。而很多服务器资源是很紧张的,你要想清楚"每台机器都跑一份"是不是真的必要。

安全方面,global 模式如果服务里绑定了宿主机的 Docker Socket(比如给容器做套娃管理),等于每一台节点都暴露了一个可控 Docker API 的能力。这时候节点被攻破的风险会放大,因为攻击者只要能访问任意一台节点的 socket,就能控制整个集群。这类高危权限类服务我通常会用--constraint node.role==manager来限制执行范围,尽量收缩暴露面。

运维习惯方面,如果你所在团队已经习惯 K8s 的 DaemonSet 概念,那么 Swarm 的 global 会给你一种天然的亲切感;如果你习惯的是传统进程管理模式,去 Systemd 里手动管理 node-exporter,那我建议你把服务迁到 Swarm 的 global 里,能少做很多重复劳动。

4. 实操演示:把 service 从单机搬到 Swarm 集群的正确姿势

4.1 初始化集群与创建第一个 mode 服务

我们直接上实操。假设你有一台服务器准备作为 Manager,执行:

docker swarm init \ --advertise-addr 192.168.1.10 \ --listen-addr 0.0.0.0:2377

看到 "Swarm initialized" 后,集群就建起来了。接着查看加入命令:

docker swarm join-token worker

把输出的docker swarm join ...复制到其他节点执行即可。生产环境建议把 Manager 节点数量控制在 3 到 5 台,我这边习惯是 3 台 Manager + 若干 Worker,因为 3 台 Manager 正好满足 Raft 多数派要求。Swarm 集群的节点角色默认情况下 Manager 也能跑业务容器,如果你希望 Manager 专门负责管控,可以设置drain状态或给服务加节点角色约束。

创建第一个服务,先试试 replicated 模式:

docker service create \ --name demo-web \ --mode replicated \ --replicas 3 \ --publish 8080:80 \ nginx:1.27-alpine

这条命令的--mode replicated其实是默认值,可写可不写,但写出来有个好处:团队里其他人看命令时,一眼就能知道这个服务的调度意图,不会误以为没有指定副本数。等它跑起来后,再用docker service ls查看运行状态,REPLICAS那一列会显示3/3。

接着创建一个 global 服务,我用一个简单的脚本服务模拟节点上的监控采集器:

docker service create \ --name node-logger \ --mode global \ --mount type=bind,source=/var/log,target=/host-log \ alpine:latest tail -f /dev/null

创建完直接docker service ps node-logger,你会发现集群里每一台节点上都有一个任务。这个服务本事不大,但它帮你直观理解 global 的行为——每一个节点上都会多一个node-logger的容器。

4.2 通过 stack / compose 文件定义 Mode

单条命令方便测试,但生产环境我更推荐用docker stack deploy配合docker-compose.yml来管理服务。尤其在多服务共存的场景下,Compose 文件的描述性能帮你把服务的类型、副本数、约束条件全写清楚,后续扩展和管理都省心。

看一下这个实际用的例子:

version: "3.8" services: web: image: nginx:1.27-alpine ports: - "8080:80" deploy: mode: replicated replicas: 2 update_config: parallelism: 1 delay: 10s order: start-first healthcheck: test: ["CMD", "curl", "-f", "http://localhost/"] interval: 30s timeout: 5s retries: 3 node-exporter: image: prom/node-exporter:v1.7.0 volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - --path.procfs=/host/proc - --path.sysfs=/host/sys - --path.rootfs=/rootfs deploy: mode: global

在这个 Compose 里,web服务走 replicated 的 2 副本,node-exporter走 global。最后执行:

docker stack deploy -c docker-compose.yml demo

它会自动创建对应服务。通过docker service ls你会看到两个服务的MODE列分别为replicated和global。

这里有一个新手容易踩的坑:Compose 文件里如果服务写的是mode: global,就不应该再写replicas字段。虽然docker stack deploy在解析这个字段时会忽略它,但某些版本(比如 Docker 20.10 之前的版本)会直接报错。而且从可读性角度讲,global 模式下写replicas: 3是非常误导的,别人看了会以为服务只会跑 3 个副本,实际出来却是节点数。我建议所有 global 服务都明确不写 replicas,只保留 mode 声明,这样语义最干净。

4.3 查看和检验服务当前 Mode

验证服务当前用的是哪种模式,不一定要docker service inspect去看很长的 JSON,直接用docker service ls就够了:

docker service ls

输出的MODE列会标注replicated或global。如果想看具体调度在哪些节点,用:

docker service ps demo_web docker service ps demo_node-exporter

看NODE列,global 的服务所有节点都有任务;replicated 的服务只在你选定的少量节点上有任务。还有一个细节是,replicated 服务的任务名后面通常会带 N 个递增编号,类似demo_web.1、demo_web.2;global 服务的任务名则直接是demo_node-exporter.xxxxx(类似 secret ID),没有递增序号,这也是一个肉眼区分的方法。

4.4 修改 Mode 的正确与错误姿势

最重要的一条实操经验来了:Swarm 不支持在服务创建之后直接把 Mode 从 replicated 改成 global,或者反过来。你执行docker service update --mode global demo_web会得到一个报错,意思是--mode这个 flag 在文件 update 阶段不可修改。

改 Mode 的正确姿势是:删除服务,然后用新 Mode 重建服务。

docker service rm demo_web docker service create \ --name demo_web \ --mode global \ --publish 8080:80 \ nginx:1.27-alpine

这种"重建"式切换在生产环境需要谨慎。服务如果关联了网络、依赖了别的服务,在新服务创建完成之前流量可能出现短暂中断。如果你用的是docker stack deploy,重新执行一次部署命令并修改deploy.mode字段,Swarm 内部也会做一次"先删旧服务再建新服务"的处理,同样会有一段为空期。所以在切换前,建议评估业务容忍度,必要时选在低峰期操作。

还有个运维小技巧:如果你的服务本身定义在 Compose 文件里,切换 Mode 时只需修改 YAML 的deploy.mode,然后重新执行:

docker stack deploy -c docker-compose.yml demo

Swarm 会区分出服务的配置差异,自动重建这个服务,无需手动删除。但要注意,stack deploy 对服务名敏感,服务名不能变,变了就是创建新服务而不是更新旧服务。

5. 排错与冷知识:Mode 相关的高频坑,我基本都踩过一遍

5.1 约束条件把 global 服务锁死:副本数比节点数少

前面我提过 global 服务会受约束条件影响。有一次我往集群里加了 5 台新节点,发现某个 global 服务在新节点上一直不启动,最后排查半天才发现服务上带着一个约束:

deploy: placement: constraints: - node.labels.zone==cn-east

新节点没打这个标签,所以 Swarm 只会在满足标签条件的旧节点上维持副本。这里的"global"并不是"全节点强制撸一遍",它更像"凡是被允许的节点,一个都不能少"。想让它复制到全节点,要么给新节点补上标签,要么去掉约束再重建服务。

检查约束问题时我的习惯是用:

docker node ls --format "{{.Hostname}} {{.Labels}}"

一次性看清楚所有节点的标签,再对照服务约束。

5.2 端口映射与 global 模式共存的坑

global 服务如果带--publish或 Compose 里的ports映射,会出现一个比较隐蔽的问题。比如你的 global 服务映射了8080:80,集群里每台节点都会占用 8080 端口。此时如果另一个服务也用同样的8080:80,Swarm 会直接报端口冲突,因为每个节点上 global 服务已经占用了这个端口。

如果这个服务是 global 的,但同时你又希望负载均衡器能通过任意节点访问它,你其实不需要每台节点都做端口映射,只需在服务里发布一个端口让 Swarm 的 routing mesh 去转发就行。但问题在于 global 模式下端口发布的行为更像"每节点都绑定",不像 replicated 那样由路由网格分发。所以全局服务通常建议用--publish published=9100,target=9100,mode=host这样的 host 模式,或者干脆不发布端口,通过 overlay 网络让别的服务直接访问。

我踩过一次的真实教训:用 global 模式部署 node-exporter 时,给服务加了--publish 9100:9100,结果集群里所有节点的 9100 都被绑定了,过了一阵发现另一个想用 9100 端口调试的服务死活起不来。后来我把--publish去掉,改用 overlay 网络内的 Service 名加端口访问,一下就清爽了。

5.3 global 服务无法使用docker service scale

你是不是遇到过这种情况:想给一个 global 服务扩容,执行:

docker service scale node-exporter=10

结果返回错误,提示 global 服务是不支持 scale 或者其他含义相同的报错。这是因为 global 服务的副本数不由用户控制,而是由节点数决定,scale 这个动作在语义上就没有意义。如果你真的想让某个节点上多跑一个实例,那说明这个服务本身不应该定义成 global,用 replicated 并固定副本数反而更合适。

遇到这种需求时,我的建议是重新审视服务定位:如果是 Agent 类服务,维持 global 不变,单节点多实例的场景极少见;如果是业务类服务,改成 replicated 模式并使用replicas控制数量。

5.4 滚动更新对 global 服务的"惊群"效应

global 服务做滚动更新时,因为所有节点上都有任务,更新触发后每个节点几乎同时拉取新镜像、停旧起新,对镜像仓库的压力会突然飙升,也容易造成"更新期间整个集群短时间所有节点上的任务都不健康"的视觉效果。

Swarm 提供了一些缓解手段,比如:

deploy: update_config: parallelism: 1 delay: 30s order: stop-first

它在 global 模式下依然生效,Swarm 会分批更新任务,先处理一个节点上的任务,等待 30 秒再动下一个。所以当你发现 global 服务更新时,可以用这个参数来减小影响面。但这里要提醒:global 模式的 parallelism 语义不是"每批更新几个副本",而是"每批更新几个节点上的任务",两者效果天差地别。

5.5docker service inspect里到底能看到什么

排查问题时,我最常用的命令其实是:

docker service inspect --pretty demo_web

它会把 Mode、Replicas、约束、网络、端口映射、更新策略这些关键信息以相对可读的格式全列出来。很多新手喜欢直接看 json,容易被一长串输出淹没。用--pretty可以先快速定位问题,需要再上 raw json 深入分析。如果发现 Mode 列异常(比如原本预期 global,实际任务分布明显不是每个节点都有),优先怀疑两件事:一是服务配置里有没有约束;二是节点本身的状态是否 Active,Drain 状态下的节点不会跑新任务,已有的任务也会被调度器迁走。

6. 我踩过的最深一次 Mode 配置的坑:标记节点时的教训

这个坑我一定要专门拿出来讲。有一次我做机房迁移,要给一批新节点加标签,然后让某个 global 监控服务在新节点上跑起来。当时我的心理预期是:"把标签加上,global 服务会自动调度过去。"结果我发现服务在新节点上没有自动创建任务,一查才知道,global 服务和节点标签的关系不是实时联动的:服务创建时,调度器会扫描全部节点,把满足条件的节点作为任务落点;但如果一个节点后来才被打上标签,Swarm 不会自动重新扫描它。

解决方式有两个方向。

第一个方向,如果你用的是 Compose 文件部署的 stack,重新执行一次:

docker stack deploy -c docker-compose.yml demo

Swarm 会重新进行服务协调,发现这个节点现在满足约束条件,就会立刻把任务调度过去。这个操作对已有服务运行基本无感知,非常安全。

第二个方向,如果这个服务是单独用docker service create创建的,可以强制把服务配置更新一下:

docker service update --force demo-global-svc

--force参数会触发任务重启,同时重新评估调度策略,包括约束条件、节点标签、全局偏好等等。我那次用完--force发现新节点上的任务立刻拉起来了,任务数也从原来的 8 个变成 13 个,对应上了新加入的节点。这算是我至今觉得最实用的一个"刷新"技巧。

再补一个和标签有关系的冷知识:Swarm 的全局服务调度并不保证"每个满足条件的节点绝对有且只有一个任务"。如果同一个节点上恰好有两个满足同等条件且同名服务,Swarm 会维持每个 native 的 global 服务各一个任务。听起来有点绕,但核心意思是:global 服务的任务数量和生产节点是"一对一"的关系,不会被重复调度。这一点保证了它不会在某个节点上因为重试逻辑而启动多个实例。

7. 从 Mode 出发,Swarm 架构还有哪些东西值得挖

Mode 只是 Swarm 服务配置里的一层,但它串起来的衍生概念非常多。比如,--mode global的服务在故障转移时没有"重新调度"这个动作,因为它不允许在别的节点起新副本;而 replicated 服务在节点宕机后,调度器会尝试把任务重新调度到其他节点。这个差异后面牵涉到 Swarm 的故障处理机制、心跳检测、任务生命周期管理,每一个都是独立的坑。

再比如,global 服务配合placement.preferences能把任务更均匀地分布到不同可用区或机架里。Swarm 支持通过--placement-pref spread=node.labels.rack这类参数实现"机架感知"调度。如果你设计的服务是 global 模式,但集群节点跨多个房间、多个机柜,我极度推荐加一个这样的 spread 参数,避免所有任务挤在同一批物理机里。

还有一个非常值得实操验证的点:global 服务在网络层的表现。Swarm 的 routing mesh 默认会对所有 publish 端口的服务做负载均衡。但当服务是 global 模式且每个节点都绑定相同端口时,routing mesh 的负载均衡行为会和 replicated 模式不一样。我自己测试时发现,global 模式服务在任意节点访问 publish 端口,实际上会转发到本节点上的那个任务;而 replicated 模式的请求则可能分发到任意一个副本上。这个差异在调试多节点环境时特别重要,也是我在选型时经常提醒团队"不要把高可用入口设计成依赖 global 服务"的原因。

这些都说明,Mode 不是孤立的一个开关,它对服务的高可用设计、网络模型、标签调度、故障恢复都有连带作用。这是值得把"服务定义"这层架构吃透的原因——按我的经验,Swarm 环境里 80% 的线上事故,根因都出在最开始的定义参数上,Mode 往往是其中之一。

我这篇先写到这里。下一步我打算把 Swarm 的集群高可用设计,尤其是任务调度、故障转移和资源预留这几个环节拆开讲。如果你在看完这篇之后,对自己服务的 Mode 选择有什么疑问,建议先去把docker service inspect --pretty的输出看一眼,拿不准的再回头对照一下这篇里的选型维度,很多问题其实一眼就有答案。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询