Agent 平台

不是撑不住,是每次撑不住都要停机

平台从 Swarm 迁到 K8s 的核心理由不是功能完整度,而是增长代价——每次容量扩张都需要停机。

老集群跑了 270 个用户,用的是单机 Swarm。现在的决策是用 K8s(天翼云 CCSE 托管版)搭新集群,只接新用户,老 Swarm 冻结。这个选择看起来很标准——当然要上 K8s 了。但真实的理由不是"K8s 功能更完整",而是"Swarm 在增长路上的停机代价无法接受"。

容量上限与扩容的代价

Swarm 单节点可以跑 432 个容器(现网实测)。老集群 270 用户对应 270 个容器,还算轻松。但架构是 1 用户 = 1 容器,目标规模是四位数用户。也就是说,最终要跑四位数容器。

这不只是节点数的问题。问题在网络。Swarm 内置的 overlay 网络(gwbridge)有容量上限。当容器数逼近上限时,添加新容器需要扩容 gwbridge——这是一个网络级操作,不能在线扩展,必须停机重建

这不是偶发维护,而是必然会反复碰上的扩容事件。实际碰过这个坑(FA-012 的经历):当 gwbridge 容量不够,无法添加新容器,唯一的办法就是停掉整个集群,手工扩容网络,重新启动。一次停机下来,不只是那一刻的业务中断,而是周期性地陷入"快要撑不住就停机扩容"的循环。

现网 05 下旬 270 用户到 05-25 的 379 个 service,两周内增长 40%。这样的增速外推,容量墙会频繁碰到。当容器数从 270 扩到 400、500、更多,在单个 gwbridge 的容量上限框架内,每次都需要网络重建。每一次都是停机。Swarm 没有办法避免这个循环——架构的天花板是固定的。

单点故障与缺失的调度层

Swarm 的故障转移很基础。节点掉线,那台机器的容器就掉线,没有自动转移。想要高可用,需要靠上层应用做心跳和重连。

K8s 有调度层。Pod 宕机或节点故障,调度器自动拉起新副本。对于这个场景——用户容器本身是无状态的(数据在外挂卷上)——自动重调度能大幅降低故障时间。特别是在四位数用户的规模下,"某个用户的容器挂了"这种低级故障完全不应该触发告警。

Swarm 没有这个能力。

存储的跨节点瓶颈

老集群用的是节点本地的 Docker volume(docker volume vol-<userId>)。每个用户的数据就住在某台机器的磁盘上。这意味着:

  1. 无法迁移。用户容器只能跑在那台机器上。节点满了?要么扩新节点并重新分配用户,要么受限于现有分布。
  2. 无法多副本。同一用户的容器无法在多个节点上同时运行(数据一致性)。高可用做不了。

新方案用 SFS Turbo(NAS)。用户数据存在共享存储上,任何节点的容器都能挂上。这提供了:

  • 容器可以迁移和重调度
  • 多副本有了存储基础
  • 节点故障时数据仍在

滚动升级的成本

老集群 379 个 service(05-25 实测),逐个更新镜像需要 6 小时 42 分(FA-013)。这是因为 Swarm 的 docker service update --image 是串行的,一个 service 一个 service 更新,两个 service 之间要等待它完全稳定。每个 service 的更新时间不长(几秒到几分钟),但乘以 379 就成了接近 7 小时的操作。

K8s 的 StatefulSet 或 Deployment 支持配置并发度。可以配置同时更新 10 个、20 个 Pod,甚至 50 个。滚动更新的总时间取决于最慢的那个 Pod 的启动时间,而不是 Pod 总数。这和 Swarm 的串行更新是完全不同的量级。

从 6 小时 42 分到可并发的升级方式,这对日常开发效率的影响是根本性的。尤其是要频繁迭代、测试新镜像时。每一次新版本上线,Swarm 都要等一个接近 7 小时的窗口,这会成为开发速度的瓶颈。K8s 消除了这个瓶颈。

健康检查与自动修复

Swarm 的健康检查能力很有限。主要靠端口监听和进程存在性。应用启动了、端口在监听,Swarm 就认为健康。但一个应用可能端口开了、进程活着,内部逻辑却已经卡死。

K8s 的 readiness probe 和 liveness probe 可以执行命令、发 HTTP 请求。这样就能真正检测"这个容器能处理请求吗",而不只是"进程还在吗"。

探测失败时,K8s 会自动杀掉容器重启。这在无状态应用场景下非常有效。Swarm 需要外层监控系统来做这个事。

时间敏感性

当前规模是 270 用户,两周增长 40%(到 379 个 service)。这样的增速外推,目标规模四位数用户意味着持续高增长。在这个成长期,Swarm 的网络扩容停机代价会反复出现,每一次都会打断业务。等规模更大时,停机影响会更严重、数据迁移工作量更大。

K8s 没有这样的容量壁垒。同一个集群,从几十个 Pod 扩到几千个 Pod,只需要加节点。网络、调度、存储都是弹性的,无需停机。

这就是为什么现在做迁移是时间敏感的。当下的工作量相对可控;等到用户数翻倍或翻三倍,迁移的代价会指数级上升(既有用户的数据迁移、关键增长期的双平台维护风险)。

决策的框架

对比两条路的总成本:

  • 路 A(继续打补丁):在 Swarm 上增加节点、优化配置、加监控系统来补偿不足。但每到一定规模,网络扩容的停机代价不会减少。长期成本是运维压力 + 周期性停机。
  • 路 B(一次迁移):现在投入迁移工作,切到原生支持这些能力的平台。前期工作量大,但后续增长时基础设施自动适应。

当下的工作量还在可控范围。如果等到用户数翻倍或更多,成本会更高(迁移数据量大、影响用户更多、迁移期间的风险更大)。

这就是为什么现在做迁移,而不是等。不是 K8s "更流行",而是继续在 Swarm 上增长,每一次容量瓶颈都要停机,这个代价在时间尺度上是递增的。Swarm 没有办法绕过这个约束——架构的天花板就是天花板。

K8s 的新问题

迁移当然不是免费的。K8s 引入了新的复杂度:

集群管理复杂度上升。现网 Swarm 是单机。K8s 即使用托管版(无需自己维护 etcd 和 master),节点管理、网络规划、存储配置都比之前复杂。

共享存储的新故障模式。老 Swarm 用本地磁盘,故障隔离。新架构用 SFS Turbo(NAS),所有节点的容器都通过 NFS 挂载同一存储。这提供了跨节点调度的便利,代价是共享存储成为关键路径。NFS server 故障、网络拥塞、单个节点的 NFS 挂载超时或 hang,都会拖垮相关容器——这是迁移前就能预见、但只有真实跑起来才能验证的风险。这类故障需要更精细的网络监控、存储多副本(尤其是 RDS 和 Redis 直接从 HA 单机开始)、以及节点级的故障转移能力。

迁移期间的双平台维护。新 K8s 集群上线,老 Swarm 继续跑现网用户。应用代码要同时支持两种编排器(Swarm 和 K8s)。新功能开发既要在 Swarm 上实现,也要在 K8s 上实现。这段时间的开发和测试工作量翻倍。

但这些都是可管理的风险。NFS 故障可以通过更好的监控、存储多副本、主备转移来缓解。共享存储是现代云原生的标准架构,业界经验充足。双平台维护的代价是时间有限的——一旦新集群稳定、旧 Swarm 下线,这块工作就消失了。

反过来,留在 Swarm 上,网络扩容停机的代价会一次次出现,直到彻底无法扩展。

那不是一个可以解决的问题。那是架构的天花板。

星野的头像

星野 XINGYE

一个人维护 AI 平台的工程师。这里记录 63 篇复盘:18 份故障档案、OTA、架构演进与工作流。