← All posts

人人都说要上 serverless。我们却保留了那个大部分时间都在闲置的 Kubernetes 集群

Authagonal·July 5, 2026
authinfrastructurekubernetesaksserverlessazurecost

这条建议到处都是,听起来显然没错。你为流量起伏不定的租户运行认证。你全天候为一个 Kubernetes 集群付费。Azure Container Apps 会把你缩容到零,只按你的实际用量计费。别再为闲置付钱了。

我们认真对待了它。我们核算了迁移到 Azure Container Apps 的成本,仔细审视了它能给我们带来什么,最后留在了 AKS。下面是理由,因为这并不是你看着集群的利用率曲线能猜到的那种理由。

这条建议是对的,只是针对一种我们并不拥有的工作负载

Serverless 容器非常适合无状态、突发式的请求处理:每个请求都相互独立,实例是"牲口",零流量就该是零账单。这描述了大量的 Web 后端。

它描述不了一个认证骨干。我们的认证骨干并不像无状态应用那样闲置。它持有集群领导权,运行着协调层,由该层决定哪个副本去执行单例工作,比如保留期清扫和 webhook 巡检。(如今我们用一个 blob lease 来选举那个 leader,不再用 gossip,那是另一个故事。)集群安静并不意味着它无事可做;它意味着它正待命去校验下一个 token,并继续当那个 leader。安静和闲置不是同一种状态。

我们没有搬家就消除了闲置账单

下面这点才是决定性的:我们想要摆脱的那笔成本,有一个比重做平台便宜得多的修法。

烧钱的,是在流量集中于工作时段时却仍 7×24 运行的节点。于是我们让开发集群在无人使用时释放资源(夜间和周末关机,按需重新拉起),并把节点池切换到一个更便宜的 SKU。这就削掉了 serverless 承诺要消除的那大部分闲置开销,而它只花了我们一次配置改动,而非一次迁移。当你想要的节省在原地就能实现时,为了追逐同一个数字而重做平台,就是用大量风险去换一个你早已拿下的差额。

这个教训可以推而广之:先给修法定价,再给重做平台定价。"别再为闲置付钱"是一个目标,不是一套架构,而达成它最便宜的方式往往是一个调度器加一个 SKU,而不是一套新的运行时。

Scale-to-zero 与一个必须持有 lease 的骨干相抵触

哪怕把成本搁在一边,scale-to-zero 对这种工作负载在两个方面都是实打实地错的。

第一,冷启动落在了最糟糕的那条路径上。要付冷启动"税"的那个请求,是某个正想登录的人,而"你的登录之所以慢,是因为我们的认证服务在睡觉",不是一句你想交付出去的话。

第二,领导权和 scale-to-zero 直接冲突。你没法从一个已被缩容掉的实例上持有 lease。一个本职就是始终恰好有一个活着的 leader 的骨干,并不想要一个本职就是在实例看起来安静时把它们移除掉的运行时。我们将不得不与平台的核心行为对抗,才能保住我们自己的行为。

那个运行时会夺走我们正在使用的三样东西

即便在能跑通的地方,迁移也不是免费的;你会继承托管运行时的沙箱,而我们依赖的一些东西恰被它的沙箱封死:

  • Twingate。 我们通过一个 Twingate 连接器访问私有资源。托管容器沙箱不会运行它,于是我们就得重新发明一套我们早已拥有的私有网络访问。
  • 我们的构建路径。 我们流水线的一部分依赖 Docker-in-Docker 和针对私有 registry 的 az acr build,两者都被沙箱禁止。这是一整套要重建的构建系统,而不只是一个要更换的部署目标。
  • 跨云控制。 我们运行着一个 AWS 备机,通过联合 JWKS 来校验由 Azure 主端签发的 token,并以 Cloudflare 作为故障切换的仲裁者。这需要一种网络与放置控制,而托管运行时会刻意将其隐藏起来。

这其中的每一样,都是我们仅仅为了回到自己已经身处之地而不得不写的变通方案。迁移真正的成本不在于切换本身;而在于把沙箱夺走的每一项能力重新挣回来。

省成本是有尾巴的,而我们付了这条尾巴

留下来同样并非毫无代价,照实说才算公道。夜间释放节点给了我们一个在常开集群上永远不会见到的故障:冷节点上首次拉取镜像时的 token 竞态(就是 AKS issue 4052 那个),它偶尔会卡住一个在集群重新上电后正起来的 pod。我们用一个更长的 rollout 超时把它修好了,而在生产环境里,则靠不像开发环境那样去释放节点来解决。

这才是权衡真正的形态。每一条路径都拖着一条故障模式的尾巴;问题在于你能否看见并修复它们。在 AKS 上,冷节点竞态是可观测、可修复的。而你从托管运行时的内脏里继承来的那些怪事,则属于你开一张支持工单、然后干等的那一类。

我们带走的规则

两点,超出我们自身也用得上。别为了逃离一笔你在原地就能干掉的成本而迁移;先给原地修法定价,因为一个调度器加一个更便宜的 SKU,多数时候都胜过一次重做平台。还有,让运行时去匹配工作负载的形态:serverless 奖赏无状态与突发,惩罚有状态与常开,而一个握着你签名密钥和集群领导权的认证内核,铁定属于后一种。

我们并不反对 serverless。我们无状态的那一大片表面,放在它上面会过得很好。但握着你的密钥、并决定谁来运行那些破坏性作业的那一部分,将继续运行在无聊、常开、可观测的基础设施上。有时候,那个看起来闲置的集群才是便宜的选择——只要你把为了离开它而必须重建的一切都算进去。

你的登录背后那套常开、可观测的基础设施是一项特性,而非疏漏。当你把认证交给 Authagonal 来运行,而不是自己去运维那套 backplane 时,交出去的正是这部分。