Skip to content
个人学习网站

Agent Sandbox OSS

给长时间运行、数据密集型 AI Agent 用的 Kubernetes 运行时

为什么做

把 Agent 放进生产环境时会撞上三件事:共享进程既不安全也保不住 QoS,临时拉 pod 冷启动要等几十秒,节点一挂正在跑的中间状态就没了。这个项目是我把这三个问题逐个拆开、一层层验证的过程——七个实验,每个只解决上一个暴露出来的那一个问题。

主要功能

预热池:百毫秒级接管

预先拉起一批 sleep 状态的 pod,请求进来直接认领,跳过调度、镜像拉取和容器初始化。同一条链路上按需创建要 45–90 秒。确切数字取决于机器与池子大小,接口会返回当次的实测值。

工作区与计算分离

用户状态放在 PVC 或远端 checkpoint 上,pod 只是执行体。手动删掉正在跑的 pod,新 pod 重新挂载同一个工作区接着往下跑。

拉模式调度

不再由分配器把任务推给指定 pod,改成 pod 自己去队列认领。双重调度和抢占问题随之消失,不需要 K8s Lease 或 Redlock。

运行时隔离

通过 RuntimeClass 把不受信任的负载换到 gVisor / Kata 上跑,用启动时间换一条不共享内核的边界。

七个渐进式实验

从最朴素的单 pod 开始,每一步都先制造故障、再引入组件,架构演进的全过程留在仓库里。

起点

Agent 跟普通 Web 请求不一样:它跑得久、吃内存、会写文件,还会执行模型现场生成的代码。把它塞进一个共享进程里,第一天就能撞见两件事——一个任务 OOM 把别人一起带走,以及一段恶意 payload 顺手读到了挂在容器里的 secret。隔离不是优化项,是入场券。

但隔离一上来就要付代价,而每一次付账都会暴露下一个问题。这个仓库记的就是这条链。

七步是怎么走的

步骤 撞到的墙 这一步的答案
1 单 Pod 任务互相阻塞、OOM 连坐,恶意代码能读到 secret 建立基线,确认必须做容器级隔离
2 按需创建 TTI 从 0.5 秒飙到 45–90 秒,APIServer CPU 飙升、etcd 写延迟 看清冷启动是物理限制,KubeAPI 不能进同步路径
3 温池 速度回到百毫秒级,但多了一批空转 pod 用冗余换延迟,开始算容量与成本的账
4 工作区分离 pod 一死,跑了一半的分析就没了 状态搬到 PVC / checkpoint,pod 变成可替换的执行体
5 推改拉 分配器要处理抢占、锁和调度冲突 worker 自己从队列认领,顺带做出优先级分层
6 硬隔离 共享内核下,恶意负载仍能耗尽节点甚至尝试逃逸 换 RuntimeClass 上 gVisor / Kata,量启动时间的代价
7 混沌 前六步各自成立,合起来未必扛得住 杀节点、杀队列主节点,量 MTTD / MTTR / 掉线率

三个真正吃透的取舍

预热池的账不是技术账。 从几十秒到百毫秒级,快了数百倍,但代价是一批常驻空转的 pod。这一步做完,问题就从“怎么让它快”变成了“预热多少个才划算、怎么随负载动态伸缩”——这是经济学问题,不是调优问题。

Pod 会死,上下文不能死。 把工作区从 pod 里拆出来之后,故障演练才有意义:手动删掉正在跑的 pod,新 pod 挂上同一份工作区继续执行,衡量的是恢复用时和数据一致性,而不是“有没有挂”。

不做调度,才解决得了调度。 推模式下分配器要知道谁空闲、还要防抢占,于是引入锁;改成 worker 主动拉取之后,这些问题不是被解决了,是不存在了。批处理系统兜兜转转都会走到这一步。

怎么验证的

最后一步把前面所有组件合起来做混沌实验:维持数百个活跃 session,然后杀掉集群中三成节点、再杀掉队列的主节点,观察系统多久发现任务停滞(MTTD)、工作区重新绑定到新 pod 要多久(MTTR)、多少用户真的看到了错误。不做这一步,前六步都只是“单独看起来对”。

现在的状态

在写。接口还会变,也还没有 release。代码全部开源,欢迎在仓库里提 issue 讨论设计上的问题。