跳到主要内容

笼子先于事故:GKE Agent Sandbox 看完说两句

锈剑
锈剑

· 阅读约 4 分钟

上周翻到 GKE Agent Sandbox,配套的开源控制器放在 kubernetes-sigs 下面。第一反应不是“又一个新功能”——是终于有人把“AI 生成的代码不能裸跑”当基础设施问题来做了,而不是一句“注意安全”写在文档末尾。

这个区别很重要。

我见过太多团队接 agent 的方式:生成一段代码,扔到跑着正经业务的节点上跑,理由是「就跑一下,很快的」。

很快的。

上次这么说的那位,那段“就跑一下”的脚本现在还在每周扫一遍全公司内网——没人记得它为什么有这个权限。这个剧本我看过不止一遍了。

所以 Agent Sandbox 默认网络策略是 deny-all,这条我要单独拎出来夸。不是客气地夸。

默认拒绝、想出去显式写规则——安全这行的老规矩:默认关,要开自己开。但这默认会咬人,第一个踩坑的肯定是你自己。agent 上来第一件事多半是 pip install,出站到 PyPI 被掐,然后你半夜在调网络策略,骂谁呢,骂自己选的这个默认。

NetworkPolicy: default deny-all

说句实话:宁可调试半小时,也别默认全通。调试的成本是半小时,全通的代价是某个你不知道的时间点、某个你不知道的出站请求。这两笔账不是一个量级的。

隔离也没糊弄。标准容器、gVisor、Kata 三档,托管版强制 gVisor。gVisor 那个用户态内核,逃逸难度和共享内核不是一个量级。给不可信代码用的笼子,钢筋比纱窗合适。

架构上四个 CRD:Sandbox、SandboxTemplate、SandboxClaim、SandboxWarmPool。前三个是常规剧本——实例、蓝图、申请,见怪不怪。第四个 WarmPool 才是真解决问题的:池子里预热着一堆 Pod,claim 一来直接分,不用等冷启动。不然 agent 每次要沙箱都干等,那个延迟够用户把标签页关了。

但预热池这东西,我用过类似机制,第一课就是账单。

每个空闲 Pod 都在烧 CPU 和内存。你池子开多大?开小了高峰排队,等于白预热;开大了,半夜三点没人用的时候,几十个空 Pod 在那儿安静地烧钱。这不是 bug,是这个模式的固有税。上这套之前先把成本模型算清楚——这数没人替你算,云厂商的 pricing 计算器不会告诉你「warm pool 闲着也是钱」。

再泼一盆冷水:宣传说毫秒级分配,实际是毫秒级分配 ≠ 亚百毫秒可用。真跑起来几百毫秒到几秒是常态。如果你的场景是 agent 循环里每步都进沙箱、对延迟敏感的实时交互,别指望这个。它适合「agent 偶尔干点脏活」,不适合塞进每个请求的关键路径。

沙箱本身有状态、有稳定主机名、能挂持久存储,比“跑完即扔”的 Docker 顺手多了。但有个坑:会话崩了之后的垃圾回收,你自己定策略,TTL 只能辅助。一堆 agent 各自 claim 了一堆沙箱、然后 agent 自己挂了没人还——这些孤儿沙箱谁来扫?不扫的话,配额和存储就这么一点点漏掉。

灵活给了你,垃圾场也给了你。

扯远了,回到正题。监控这块也得提一句。短命沙箱的日志、指标、成本归属,现有那套面向长期工作负载的 K8s 监控基本不匹配。沙箱活八分钟就没了,dashboard 上它连一条像样的曲线都攒不出来。这块自己搭。

开源版 Apache 2.0,能自托管到气隙环境;托管版有 SLA,但要 1.35.2 以上的集群和开 gVisor 的节点池。两条路都通,看你是想自己养控制器还是让 Google 养。Python SDK 对着 LangChain 那套 agent 框架,Go SDK 给平台工程师——分工倒是清楚。

总的判断:方向对,默认狠,值得在「agent 跑不可信代码」这件事上认真评估一轮。

但我真正想说的是这个。每次有人吹「AI agent 全自动干活」,我都想问一句:它生成的代码跑在哪?

跑在一个和你的数据库同 VPC 的裸节点上,还是跑在一个 deny-all、gVisor 隔离、claim 完自动回收的笼子里?前者不叫自动化,叫埋雷。后者才敢让人睡觉。

Agent Sandbox 至少把笼子做成了标准件。以前你得自己拿 NetworkPolicy 和 gVisor RuntimeClass 手搓一套,搓得好的没几家——现在有作业能抄了。哪怕不用托管版,开源控制器也够你参考隔离边界怎么画。

本期教训:给 agent 上生产之前,先回答三个问题——它跑在哪、能碰到什么、挂了谁收尸。答不上来的那次故障,接电话的是你。

锈剑
锈剑

接太多半夜电话的系统老兵,第一人称短段干冷吐槽,戳管理鸡汤与行业废话。

查看主页 →