Docker 基础体系 · 第 60/70 篇。示例以现代 Docker Engine、BuildKit 与 Compose 规范为基础,并明确 Linux 容器边界。
Docker Swarm 基础与边界:Service、Task、Overlay、Secret 和滚动更新
Docker Swarm 是 Docker Engine 内置的集群编排模式。它把多个 Docker Engine 组织成一个集群,由管理节点维护期望状态,由调度器把工作分配到节点,再由各节点上的 Agent 创建和监控容器。
Swarm 适合解释和实践以下问题:
- 一个服务如何从“运行一个容器”变成“维持多个副本”;
- 容器为什么会被重新创建,以及如何被调度到其他节点;
- 不同节点上的容器如何通过 Overlay 网络通信;
- 密码、证书等敏感配置如何传入容器;
- 服务更新时如何逐批替换旧任务;
- Swarm 与
docker compose up、镜像仓库、持久化状态和生产交付之间的边界在哪里。
本文以现代 Docker Engine、BuildKit 和 Compose 规范为背景,但示例明确针对 Linux 容器 Swarm 集群。Windows 容器、Windows 节点上的网络和 Secret 文件行为不能直接套用本文结论。
1. Swarm 的基本模型:集群、节点、服务和任务
1.1 Swarm 集群和节点角色
执行以下命令会把当前 Docker Engine 初始化为一个 Swarm:
docker swarm init --advertise-addr 10.0.0.11
成功后通常会输出一个用于加入其他节点的命令,例如:
docker swarm join --token SWMTKN-... 10.0.0.11:2377
其中:
10.0.0.11是其他节点能够访问的管理节点地址;2377/tcp用于 Swarm 管理面通信;- 加入命令中的 token 用于节点认证,不应公开粘贴到公共日志中;
- 初始化节点默认同时是 manager 和 worker。
在 Linux 防火墙和云安全组中,常见需要放通:
2377/tcp:集群管理面;7946/tcp和7946/udp:节点发现与控制通信;4789/udp:Overlay 数据面,默认 VXLAN 通常使用该端口。
实际端口和加密选项应以部署方式、Docker 版本和网络环境为准。只开放 2377 而忽略 Overlay 所需通信,可能导致节点已经成功加入,但跨节点容器无法通信。
查看节点:
docker node ls
典型输出:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS
abc... * manager-1 Ready Active Leader
def... worker-1 Ready Active
ghi... worker-2 Ready Active
Ready 表示节点当前可参与集群;Active 表示调度器可以向该节点放置任务;Leader 表示该 manager 当前是 Raft 共识组的领导者。
Swarm manager 负责:
- 保存集群状态;
- 选举 Raft leader;
- 接受服务创建、更新和删除请求;
- 调度任务;
- 把服务的期望状态传播给节点。
worker 上的 Docker Engine Agent 负责:
- 接收分配给本节点的任务;
- 创建、启动和停止容器;
- 把任务状态汇报给 manager;
- 持续尝试把本节点任务恢复到指定状态。
manager 也可以运行工作负载,但生产集群中经常使用:
docker node update --availability drain manager-1
使 manager 只管理集群而不接受新任务。drain 会把已经运行在该节点上的普通服务任务迁走,但不会让 manager 失去管理功能。
1.2 Raft 仲裁与管理面故障
多个 manager 使用 Raft 保存一致的集群状态。若 manager 数量为 ,形成多数派所需的节点数为:
例如:
- 1 个 manager:需要 1 个;
- 3 个 manager:需要 2 个;
- 5 个 manager:需要 3 个。
如果 3 个 manager 中有 2 个同时失效,剩下的 1 个通常无法提交新的集群状态。此时可能无法执行创建服务、扩容或滚动更新,但已经在 worker 上运行的容器不一定立即停止。原因是:
- 任务本身由 worker 上的 Docker Engine 运行;
- 新的调度和状态提交依赖 manager 的 Raft 多数派。
因此,“管理面不可用”和“业务容器立即不可用”是两个不同故障。恢复 manager 多数派后,集群才能继续正常收敛。不要在不了解 Raft 数据状态的情况下随意执行破坏性的集群重建操作。
2. Service 和 Task:期望状态如何变成容器
2.1 Service 是期望状态
Swarm 中的 Service 是一组具有相同规格的任务,以及对这组任务的期望状态描述。
例如:
docker service create \
--name web \
--replicas 3 \
--publish published=8080,target=80 \
nginx:1.27
这条命令表达的不是“启动一个 nginx 容器”,而是:
创建名为
web的服务,使它长期保持 3 个使用nginx:1.27镜像、监听容器 80 端口并发布宿主机 8080 端口的任务。
查看服务:
docker service ls
可能得到:
ID NAME MODE REPLICAS IMAGE
p3... web replicated 3/3 nginx:1.27
3/3 的含义是当前运行中的任务数为 3,期望任务数也是 3。它不是三个“固定容器名”,而是三个任务槽位。
服务可以用声明式方式描述:
services:
web:
image: nginx:1.27
deploy:
replicas: 3
restart_policy:
condition: on-failure
在单机 Compose 中执行:
docker compose up
不会启动 Swarm Service;它启动的是当前 Docker Engine 上的普通 Compose 容器。只有使用 Swarm 部署命令时,deploy 相关配置才进入 Swarm 服务模型:
docker stack deploy -c compose.yaml demo
因此,Compose 文件格式相同,不等于运行模型相同。
2.2 Task 是 Service 的一次任务实例
Task 是 Service 期望运行的一个具体实例。它通常对应一个被 Swarm 管理的容器,但任务本身还包含:
- 所属 Service;
- 任务槽位;
- 目标节点;
- 镜像和命令;
- 网络、挂载、Secret 等配置;
- 当前状态;
- 失败原因和重启历史。
查看任务:
docker service ps web
可能输出:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE
a1... web.1 nginx:1.27 worker-1 Running Running 2 minutes ago
b2... web.2 nginx:1.27 worker-2 Running Running 2 minutes ago
c3... web.3 nginx:1.27 worker-1 Running Running 2 minutes ago
如果 web.2 所在节点故障,Swarm 不会把同一个容器“搬到”另一个节点。容器不能在节点间迁移。调度器会创建一个新的任务,例如:
d4... web.2 nginx:1.27 worker-1 Running Running 10 seconds ago
b2... web.2 nginx:1.27 worker-2 Shutdown Rejected 1 minute ago
这里仍然是任务槽位 web.2,但任务 ID 已经变化。任务是不可变的执行记录;失败后通常创建替代任务,而不是修改旧任务使其复活。
可以把 Service 的基本收敛过程写成:
当差值为正,调度器尝试创建任务;当差值为负,调度器停止多余任务。实际调度还必须满足节点资源、标签、约束、端口和卷等条件。
例如,期望副本数为 3,但只有两个节点允许运行该服务,且每个节点最多只能容纳一个副本,那么结果可能长期为 2/3。这不是 Swarm 忽略了配置,而是约束条件使期望状态暂时不可满足。
2.3 调度约束、偏好和资源边界
可以用节点标签限制任务位置:
docker node update --label-add disk=ssd worker-1
服务使用约束:
docker service create \
--name db \
--constraint 'node.labels.disk == ssd' \
--mount type=volume,source=dbdata,target=/var/lib/postgresql/data \
postgres:16
约束是硬条件。若没有满足 disk=ssd 的节点,任务会处于 Pending 或 Rejected 等非运行状态,而不是自动忽略约束。
资源限制和预留也会影响调度:
services:
api:
image: example/api:2025-01-01
deploy:
replicas: 4
resources:
reservations:
cpus: "0.50"
memory: 256M
limits:
cpus: "1.00"
memory: 512M
reservations 用于调度判断,表示任务至少需要多少资源;limits 是运行时上限。若节点可分配资源不足,任务不会被安排到该节点。实际内存不足时,Linux 内核仍可能触发 OOM,导致任务退出并被重启。
3. Overlay 网络:跨节点容器如何通信
3.1 Overlay 的作用和范围
普通 bridge 网络只存在于单个 Docker Engine。若 worker-1 上的容器要访问 worker-2 上的容器,就需要一种跨 Docker 主机的虚拟网络,Swarm 使用 Overlay 网络。
创建网络:
docker network create \
--driver overlay \
--attachable \
app-net
--attachable 允许普通容器使用该网络;没有该选项时,主要供 Swarm Service 使用。
在 Stack 文件中,网络通常写成:
networks:
app-net:
driver: overlay
服务加入该网络后,Swarm 会为不同节点上的任务建立逻辑上的二层网络。Linux Docker 的常见实现使用 VXLAN 封装,但 VXLAN 属于实现细节,不能把某个内核接口表现当作应用层协议保证。
Overlay 中至少存在两类通信:
- 控制面:传播网络成员、端点和服务发现信息;
- 数据面:真正承载容器之间的业务数据包。
可以使用加密数据面:
docker network create \
--driver overlay \
--opt encrypted \
secure-net
encrypted 通常会增加 CPU 和网络开销。它不是对应用协议的替代,也不能解决容器内应用自身的认证授权问题。是否启用应结合节点间网络是否可信、性能和合规要求验证。
3.2 服务发现:VIP 与 DNSRR
默认情况下,Swarm Service 使用 VIP(Virtual IP)模式。服务名解析到一个虚拟 IP,访问该 VIP 时由 Docker 的服务发现和负载均衡逻辑把连接转发到任务。
例如:
docker service create \
--name api \
--network app-net \
--replicas 3 \
example/api:2025-01-01
同一 Overlay 网络中的其他服务可以使用:
http://api:8080
而不是查找具体任务 IP。
也可以使用 DNSRR:
services:
api:
image: example/api:2025-01-01
networks:
- app-net
deploy:
endpoint_mode: dnsrr
DNSRR(DNS round-robin)返回多个任务地址,由客户端选择目标。它适合客户端本身支持多地址发现的场景,但不能假设所有客户端都会正确地轮询、剔除失效地址或重新解析 DNS。VIP 模式通常对普通 HTTP 客户端更透明。
服务名解析只在加入同一网络的容器之间成立。宿主机直接执行:
curl http://api:8080
通常不能解析 Swarm 内部服务名;这是容器网络命名空间与宿主机 DNS 范围不同造成的。
3.3 发布端口与 Routing Mesh
创建服务时:
docker service create \
--name web \
--replicas 3 \
--publish published=8080,target=80 \
nginx:1.27
这里:
published=8080是对外暴露的端口;target=80是容器内服务监听的端口。
默认发布模式是 ingress,也就是 Routing Mesh。访问任意一个 Swarm 节点的 8080,流量都可能被转发到集群中某个健康任务,而不要求该节点本地正好运行该任务。
客户端
│
▼
任意 Swarm 节点:8080
│ Routing Mesh / ingress
▼
某个 web task:80
这不代表应用获得了一个通用、高级的生产负载均衡器。它解决的是 Docker 层面的端口入口和任务转发,仍需考虑:
- 长连接和连接分布;
- 客户端源地址是否被保留;
- TLS 终止位置;
- 应用层健康检查;
- 外部负载均衡器和 DNS;
- 节点防火墙与可达性。
如果使用 host 发布模式:
services:
web:
image: nginx:1.27
ports:
- target: 80
published: 8080
protocol: tcp
mode: host
请求只会进入运行该任务的节点。对于同一节点上的服务任务,端口还会发生冲突;因此 host 模式更接近“每个节点直接监听端口”,不等价于 ingress 模式。
4. Secret:敏感配置如何进入任务
4.1 Secret 的存储和生命周期
Docker Secret 用于密码、API Token、私钥等敏感数据。创建 Secret 前,当前 Engine 必须处于 Swarm 模式:
printf 'correct horse battery staple\n' | \
docker secret create db_password -
查看 Secret:
docker secret ls
Secret 的内容不会直接出现在普通 docker service inspect 输出中。Swarm manager 将 Secret 纳入集群状态,并通过加密的管理通道发送给被授权的任务。Linux Swarm 中,任务通常在容器内通过内存文件系统暴露 Secret,而不是通过环境变量传入。
创建 Secret 后不能原地修改。若密码需要更换,应创建新名称:
printf 'new-password\n' | docker secret create db_password_v2 -
然后更新服务,使其使用新 Secret。旧 Secret 只有在不再被任何服务使用后才应删除。
4.2 Secret 在容器内的表现
Stack 文件示例:
services:
app:
image: example/app:2025-01-01
secrets:
- source: db_password_v2
target: db_password
uid: "1000"
gid: "1000"
mode: 0400
secrets:
db_password_v2:
external: true
部署前必须先创建名为 db_password_v2 的 Swarm Secret:
docker stack deploy -c stack.yaml demo
容器内通常可见:
/run/secrets/db_password
应用应读取文件内容,而不是读取名为 DB_PASSWORD 的环境变量。例如:
cat /run/secrets/db_password
会显示密码内容,因此在生产环境不要把这个命令写入日志或诊断脚本。
target 决定容器内文件名;uid、gid 和 mode 决定 Linux 文件的所有者和权限。若应用以非 root 用户运行,却没有读取权限,典型表现是:
open /run/secrets/db_password: permission denied
Secret 能减少密码出现在环境变量、命令行和 Compose 文件中的机会,但它不是应用级密钥管理的全部方案:
- 进程只要有权限读取文件,就能获得明文;
- 应用日志可能意外打印 Secret;
- Secret 被加载到应用内存后,Docker 无法控制应用如何使用它;
- 需要轮换时必须设计兼容旧值和新值的更新顺序。
4.3 Secret 与 Compose 的边界
下面的命令:
docker compose up -d
使用的是单机 Compose 生命周期。Compose 也支持 secrets 字段,但其具体实现取决于本地 Compose 和平台;它不自动获得 Swarm manager 的 Raft Secret 语义。
下面的命令:
docker stack deploy -c stack.yaml demo
才使用 Swarm Secret 和 Service 模型。Stack 文件中的 deploy、滚动更新、副本数等配置,也主要在这里生效。
5. 用 Stack 完成一个可运行的服务部署
先准备一个 Secret:
printf 'demo-password\n' | docker secret create demo_db_password -
准备 stack.yaml:
services:
web:
image: nginx:1.27
networks:
- app-net
ports:
- target: 80
published: 8080
protocol: tcp
mode: ingress
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
order: start-first
failure_action: rollback
monitor: 30s
max_failure_ratio: 0
rollback_config:
parallelism: 1
order: stop-first
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 60s
secrets:
- source: demo_db_password
target: db_password
mode: 0400
networks:
app-net:
driver: overlay
secrets:
demo_db_password:
external: true
部署:
docker stack deploy -c stack.yaml demo
Stack 会给资源增加名前缀,因此 Service 名称通常是:
demo_web
检查部署:
docker stack services demo
docker stack ps demo
docker service ps demo_web
从任意能访问 Swarm 节点的机器测试:
curl http://10.0.0.11:8080
若返回 nginx 的欢迎页面,说明至少完成了以下链路:
- manager 接受 Stack 配置;
- Service 产生 3 个副本任务;
- scheduler 把任务分配给可用节点;
- 节点拉取
nginx:1.27; - 容器加入 Overlay 网络;
- ingress 端口接收
8080; - Routing Mesh 把请求送到某个任务的 80 端口;
- Secret 被挂载到任务容器的
/run/secrets/db_password。
docker stack deploy 默认不会替你构建应用镜像。若文件中写了:
build: .
不能把它当作集群中可靠的构建步骤。常见流程是使用 BuildKit 在 CI 中构建并推送镜像:
docker buildx build \
--platform linux/amd64 \
-t registry.example.com/example/api:2025-03-08 \
--push .
然后在 Stack 文件中引用该镜像。所有可能运行任务的节点都必须能访问镜像仓库,或者镜像已经预置在节点上。多架构镜像还必须包含目标节点架构,否则任务可能在某些节点上因镜像平台不匹配而失败。
6. 滚动更新:Service 如何替换旧任务
6.1 更新不是修改容器,而是创建新任务
执行:
docker service update \
--image nginx:1.27.1 \
demo_web
Swarm 不会把已经运行的容器中的镜像文件替换掉。它会修改 Service 的期望规格,然后按更新策略逐步:
- 选出需要更新的旧任务;
- 创建或启动新规格任务;
- 等待新任务达到可接受状态;
- 停止旧任务;
- 继续下一批任务。
因此,任务 ID 和容器 ID 会变化。应用必须把容器视为可替换实例,而不能把本地容器文件系统当作永久资产。
6.2 parallelism、delay 和 order
假设服务有 5 个副本:
web.1 web.2 web.3 web.4 web.5
设置:
update_config:
parallelism: 2
delay: 20s
order: stop-first
更新过程可以抽象为:
初始:旧旧旧旧旧
批次 1:
停止旧任务 1、2
启动新任务 1、2
等待 monitor / 状态检查
得到:新新旧旧旧
等待 20 秒
批次 2:
停止旧任务 3、4
启动新任务 3、4
得到:新新新新旧
等待 20 秒
批次 3:
停止旧任务 5
启动新任务 5
结束:新新新新新
parallelism 表示每批处理多少个任务。它不是“同时最多运行多少个容器”的精确保证,因为 start-first 会使新旧任务短暂并存。
order 有两个常见值:
stop-first:先停止旧任务,再启动新任务;start-first:先启动新任务,再停止旧任务。
start-first 可以缩短因旧任务停止带来的服务空窗,但需要额外资源,并且会受到端口、卷和应用启动逻辑的限制。例如:
- 单节点只有 1 GB 可用内存,旧任务占用 700 MB,新任务无法并存;
- 使用 host 模式发布同一个端口,新任务无法在同一节点绑定该端口;
- 使用同一个独占本地卷,两个任务不能同时挂载;
- 应用不支持两个实例同时处理同一份状态。
因此,start-first 不是无条件的零停机保证。
6.3 更新成功和失败如何判定
可以配置:
update_config:
monitor: 30s
failure_action: rollback
max_failure_ratio: 0
含义是:
monitor: 30s:更新任务后观察一段时间;failure_action: rollback:更新失败时自动回滚;max_failure_ratio: 0:允许的失败比例为 0。
失败可能来自:
- 镜像拉取失败;
- 容器无法启动;
- 端口或挂载冲突;
- 节点不满足约束;
- 进程在观察窗口内退出;
- 健康检查失败并导致任务不健康。
健康检查必须由镜像或服务配置定义。例如:
services:
api:
image: example/api:2025-03-08
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 3s
retries: 3
健康检查只能说明容器内部探针是否成功,不能自动验证外部依赖、业务数据一致性或真实用户请求是否正常。一个能返回 200 的 /health,并不等于数据库迁移已经兼容、支付接口可用或消息消费没有积压。
查看更新状态:
docker service inspect \
--pretty \
demo_web
以及:
docker service ps demo_web --no-trunc
如果任务失败,--no-trunc 往往能看到更完整的错误原因,例如镜像不存在、端口冲突或健康检查失败。
7. 回滚:恢复 Service 规格,而不是恢复容器现场
手动回滚:
docker service rollback demo_web
回滚的是 Service 的上一版本规格,例如上一版本的:
- 镜像;
- 环境变量;
- 网络;
- Secret;
- 挂载;
- 更新配置。
它不是虚拟机快照,也不会恢复新版本任务在外部数据库中已经执行的写入。若新版本已经完成不可逆的数据迁移,单纯回滚应用镜像可能仍然无法工作。
Stack 文件可以配置回滚策略:
deploy:
rollback_config:
parallelism: 1
delay: 5s
order: stop-first
典型的自动失败路径是:
旧版本服务
│
▼
更新第 1 批任务
│
├── 新任务启动并保持正常
│ └── 继续下一批
│
└── 新任务失败超过阈值
│
▼
failure_action=rollback
│
▼
按 rollback_config 恢复旧规格
回滚同样需要旧镜像可拉取、节点可用、端口和卷条件满足。若旧镜像只存在于已经损坏的本地缓存中,或旧版本依赖的 Secret 已被删除,回滚也可能失败。
8. 副本、端口和共享状态的边界
8.1 副本只复制无状态计算
将服务扩容为 5 个副本:
docker service scale demo_web=5
只会增加 5 个相同的任务实例。它不会自动:
- 复制数据库数据;
- 共享本地文件;
- 让进程内存中的 Session 互通;
- 让本地上传目录在所有节点可见;
- 让定时任务自动去重。
如果应用把 Session 存在进程内存中,请求被转发到不同副本时可能表现为“随机掉线”。解决方案通常是外部 Session 存储、无状态 Token,或者经过明确验证的会话粘性方案。
8.2 本地 Volume 不是集群共享存储
下面的挂载:
volumes:
- type: volume
source: appdata
target: /var/lib/app
如果使用默认 local volume driver,它通常只存在于任务所在的那个 Docker 节点。任务从 worker-1 重调度到 worker-2 后,两个节点上的 appdata 可能是两个不同的数据目录。
因此,下面的因果链是危险的:
任务故障
→ 新任务被调度到另一节点
→ 自动挂载同名 local volume
→ 误以为拿到了原数据
实际上,新节点可能得到一个空目录。需要持久化和跨节点迁移时,应使用外部存储、支持集群的 Volume Driver,或把有状态系统放在适合其一致性模型的专用平台上。数据库的复制、故障转移和备份也不能由 Swarm 副本数替代。
8.3 定时任务和唯一消费者
把一个定时任务服务设置为多个副本,通常会导致每个副本都执行同一任务:
deploy:
replicas: 3
Swarm 的副本控制只保证有 3 个任务,不保证“每个时间点只有一个任务执行某个业务动作”。唯一执行者需要分布式锁、队列消费者竞争、数据库约束或专用调度机制。
9. 常见失败表现与诊断路径
9.1 服务长期处于 0/3
先看任务:
docker service ps demo_api --no-trunc
再看节点:
docker node ls
常见原因包括:
- 节点处于
Drain; - 约束没有匹配节点;
- CPU 或内存 reservation 不满足;
- 镜像仓库不可达;
- 私有仓库认证缺失;
- 端口已被占用;
- Secret 或 Config 不存在;
- 节点架构与镜像不匹配。
不要只看 docker service ls 的副本数字;真正的失败原因通常在任务历史中。
9.2 跨节点服务名能解析,但请求失败
这说明 DNS 服务发现可能工作正常,但不代表数据面完整。应依次检查:
docker network inspect app-net
docker service inspect demo_api
docker service ps demo_api
然后验证:
- 两个服务是否加入同一个 Overlay 网络;
- 应用是否监听
0.0.0.0而不是只监听127.0.0.1; - 应用监听端口是否与
target一致; - 节点之间的
7946和4789是否被防火墙阻断; - 容器内部是否存在额外的应用层认证或 TLS 配置。
应用只监听 127.0.0.1:8080 时,即使 Docker 已正确发布端口,其他容器也无法通过容器 IP 访问它,因为该进程只接受本地回环接口连接。
9.3 更新卡住或自动回滚
检查:
docker service ps demo_web --no-trunc
docker service inspect --pretty demo_web
重点寻找:
Rejected:调度、端口、挂载或约束问题;Failed:进程退出、探针失败或启动错误;Preparing长时间不变:镜像拉取、节点或仓库问题;- 新任务运行但业务失败:健康检查过于简单,或外部依赖不兼容。
若更新使用 start-first,还要检查是否需要额外资源。若使用 host 端口,检查新旧任务是否无法同时绑定同一端口。
10. 镜像、标签与可复现交付
使用可变标签:
docker service update --image example/api:latest demo_api
会带来不确定性:
- 不同节点拉取时可能得到不同时间推送的内容;
latest无法表达发布版本;- 回滚时难以确认原始镜像;
- 仓库认证或镜像清理可能使旧版本无法重新拉取。
更可控的方式是使用不可变版本标签,最好记录镜像 digest:
example/api@sha256:...
镜像 digest 指向具体内容,同一 digest 具有更强的可重复性。但仍需保留镜像仓库中的内容,不能因为 Service 记录了 digest 就假设仓库永远可用。
docker stack deploy 的交付链通常是:
源码提交
→ CI 使用 BuildKit 构建镜像
→ 推送带版本的镜像
→ 运行测试和安全检查
→ 部署 Stack
→ 观察 Service、Task、日志和业务指标
→ 必要时回滚 Service
Swarm 负责运行时编排,不会自动替代 CI、镜像仓库、数据库迁移工具、灰度控制、容量评估和运行手册。
11. Swarm 能保证什么,不能保证什么
能够保证的核心性质
在 manager 多数派可用、节点和镜像满足条件时,Swarm 会持续尝试使实际状态接近期望状态:
- 维持指定数量的任务;
- 在节点失效后重新调度任务;
- 按策略执行服务更新;
- 在 Overlay 网络中提供服务发现;
- 将授权的 Secret 传递给对应任务;
- 保存 Service、Task 和节点关系的集群状态。
不能自动保证的性质
Swarm 不自动保证:
- 应用接口一定正确;
- 数据库写入不会丢失;
- 本地 Volume 会跨节点复制;
- 多副本之间状态自动一致;
- 更新一定零停机;
- 回滚一定能撤销数据库迁移;
- 多个副本中的定时任务只执行一次;
- 单个健康检查成功就代表完整业务可用;
- 所有节点都能拉取私有镜像;
- 运行中的容器可以无损迁移到另一个节点。
理解这个边界的关键是区分三种状态:
- Service 期望状态:例如副本数为 3、镜像为某个版本;
- Task 运行状态:某个具体任务是否已启动、失败或被替换;
- 业务状态:数据库、队列、文件、外部 API 和用户会话是否正确。
Swarm 主要负责前两者。第三者必须由应用架构、存储系统、交付流程和运维验证共同负责。
系列导航与关联阅读
- 系列入口:Docker 完整学习路线:从镜像与容器到安全、可观测和生产交付
- 上一篇:Docker 不可变制品晋级:Digest、环境配置、验收、灰度和回滚
- 下一篇:Docker Daemon 配置:data-root、日志、代理、镜像源、TLS 和验证
- 延伸:Compose 扩容与并发:Replica、端口、负载均衡、共享状态和边界
- 延伸:Docker 生产交付体系:CI、灰度、回滚、容量和运行手册
官方资料
本文依据 Docker、OCI 与 CNCF 官方文档重新梳理;正文与生产检查清单由 WR BLOG 编写。

评论
0 条讨论