腾讯云 Cube Sandbox 实战笔记
2026-04-24。环境:Ubuntu 24.04 + AMD EPYC 7601(64 vCPU / 125 GB),宿主机 KVM;在 QEMU 开发 VM(OpenCloudOS 9,16 vCPU / 16 GB,嵌套 KVM)里装 Cube 服务;MicroVM 在嵌套 KVM 里起。所以下面的性能数据都带"嵌套虚拟化惩罚",裸金属会显著更好。
TL;DR
Cube Sandbox 是腾讯云 2026-04-21 开源的 AI Agent 沙箱底座,基于 RustVMM + KVM。核心卖点就两句话:
- 冷启动 < 60 ms,单实例内存开销 < 5 MB — 让单台 96 vCPU 机器能同时跑 2000+ 个"真 VM 隔离"的沙箱。
- E2B SDK drop-in 兼容 — 只改一个
E2B_API_URL环境变量,原本付费用 E2B 云跑的 Agent 就能无缝切到自建。
定位上,它填的是 AI Agent 执行环境这个空白:
| Docker 容器 | 传统 VM | Cube Sandbox | |
|---|---|---|---|
| 隔离级别 | 共享内核 namespace | 独立内核 | 独立内核 + eBPF 网络 |
| 冷启动 | ~200 ms | 秒级 | < 60 ms |
| 内存开销 | 低(共享内核) | 高(完整 OS) | < 5 MB(裁剪后) |
| 单机密度 | 高 | 低 | 千级/台 |
| E2B SDK | ✗ | ✗ | ✅ drop-in |
(指标来自官方 README,官方给的基准条件:≤ 32 GB 规格,50 并发创建时平均 67 ms / P95 90 ms / P99 137 ms)
为什么值得关注
LLM 跑代码必须扔进沙箱,否则随便给 Agent 一个 os.system 工具就能出事。现在业界的选择:
- Docker — 便宜快,但容器逃逸历史不少,namespace 共享内核在
kernel.unprivileged_userns_clone这类面前不够硬。 - E2B / Modal / Daytona — 云服务,按用量付费,企业数据出境也是个坎。
- Firecracker / Kata Containers — 自己搭确实能做 MicroVM 隔离,但冷启动、编排、网络隔离都得自己拼,没有现成的 Agent 视角的"一键部署 + E2B 协议"。
Cube 基本是把 Firecracker 那一类方案做成了"带 SDK 兼容层的开箱即用服务",并且把 Rust VMM 栈里能抠的每一毫秒、每一 MB 都抠了一遍。
架构概览
分六层,从上到下:
| 组件 | 角色 |
|---|---|
| CubeAPI | Rust 写的 REST 网关,兼容 E2B 协议 |
| CubeMaster | 集群编排、资源调度 |
| CubeProxy | 反向代理,按 <port>-<sandbox_id>.<domain> 解析 Host 头路由到具体沙箱 |
| Cubelet | 节点本地调度,管沙箱生命周期 |
| CubeVS | eBPF 实现的内核级网络隔离 —— 这是区别于纯 Firecracker 的关键 |
| CubeHypervisor + CubeShim | KVM MicroVM 管理 + containerd Shim v2 集成 |
代码语言构成:Rust 52% / Go 27% / C 19%(Rust 是 hypervisor 和 API 层,Go 是编排层,C 是 eBPF 程序)。
实际跑起来:踩到的坑
按官方文档四步走:prepare_image.sh → run_vm.sh → 进去 online-install.sh → 建模板 + 跑 E2B SDK。
坑 1:宿主机需要 KVM 嵌套虚拟化
Cube 自己已经是 MicroVM,但官方 dev-env 会再套一层开发 VM(OpenCloudOS 9)。所以要嵌套 KVM:
cat /sys/module/kvm_amd/parameters/nested # 我这里是 1 ✅
# Intel 机器看 /sys/module/kvm_intel/parameters/nested
如果是裸金属 Linux 服务器可以直接跳过开发 VM 这一层,online-install.sh 直接跑在宿主上。但官方脚本把 cube-proxy 塞进 Docker + 改系统 DNS + 装 mkcert 根证书,污染宿主机不小,值得用 dev-env 隔离。
坑 2:/dev/kvm 的权限会被 udev 重置
我第一次跑 prepare_image.sh,镜像下载、resize 都完了,到了启动 VM 环节挂了:
qemu-system-x86_64: failed to initialize kvm: Permission denied
原因:/dev/kvm 属于 root:kvm,我账号不在 kvm 组,手动 setfacl -m u:jinxu:rw /dev/kvm 能临时解决,但 udev 重载会把 ACL 抹掉。
稳定做法是写个 udev rule:
sudo tee /etc/udev/rules.d/65-kvm.rules <<'EOF'
KERNEL=="kvm", GROUP="kvm", MODE="0660", RUN+="/usr/bin/setfacl -m u:jinxu:rw /dev/kvm"
EOF
sudo udevadm control --reload-rules
sudo usermod -aG kvm $USER # 新 session 生效
当前 session 没 kvm 组的话,用 sg kvm -c './prepare_image.sh' 临时取组运行就行。
坑 3:dev-env 脚本依赖 ripgrep 却没写进错误提示
prepare_image.sh 用 rg 在 QEMU 串口 log 里找 sshd 启动失败字样。系统没装 ripgrep 的话会在 need_cmd rg 处 fail fast。Ubuntu 24 要 sudo apt-get install ripgrep。
坑 4:镜像体积
- OpenCloudOS 9 cloud image:原始 ~500 MB,resize 到 100 GB(稀疏分配,实际占用 ~1 GB)
online-install.sh下的 release 包cube-sandbox-one-click-<sha>.tar.gz:还得几百 MB- MySQL 8 + Redis 7 + cube-proxy 镜像:再几百 MB
整个 setup 至少预留 5 GB 磁盘 + 2 GB 内存给 dev VM(我给了 16 GB)。
部署层设计的几处小亮点
- E2B 协议走 HTTP/3000,CubeProxy 走 HTTPS/443 + CoreDNS:沙箱内服务通过
<port>-<sandbox_id>.cube.app域名暴露,CubeProxy 用 mkcert 生成cube.app证书,注入 CoreDNS 做本地解析,这个拆分让沙箱内起的 Web 服务能直接用 HTTPS 访问,不用手搓 TLS。 - CubeShim 走 containerd Shim v2:把 MicroVM 塞进了标准容器运行时接口,意味着理论上
crictl、nerdctl这些工具都能当调试入口。 - autostart systemd unit 默认装但不 enable:
cube-sandbox-oneclick.service装好了但默认不自启动,需要./cube-autostart.sh enable明确开启。这个设计挺克制。
实测数据(嵌套 KVM 下)
跑 10 次顺序冷启动 + 4 路并发 + run_code 延迟。模板基于官方 ccr.ccs.tencentyun.com/ags-image/sandbox-code:latest,含 Python 3.12.13 + Jupyter kernel + numpy 等。
冷启动延迟(顺序 × 10,客户端端到端)
| 指标 | 值 |
|---|---|
| mean | 917.2 ms |
| median | 921.7 ms |
| min | 896.6 ms |
| max | 939.4 ms |
| stdev | 15.3 ms |
σ 只有 15 ms,几乎零抖动,比我以前测 Docker run 都稳。官方裸金属基准是 avg 67 ms / P95 90 ms,嵌套 VM 里 917 ms 意味着大约 ~13x 纯嵌套虚拟化惩罚,这个惩罚跟单层 VM 正常预期差不多。
其中 CubeShim 上报的 MicroVM BootVm 耗时 69 ms(和官方 <60 ms 一致),CreatePodSandbox 累计 9.7 s(包含 pmem/vsock 设备激活 — 嵌套 VM 下设备激活明显慢)。**应用级快照(v2 appsnapshot)**把这个冷启动路径绕过去,从而稳定到 900 ms 区间。
run_code("1+1") 延迟(同一 sandbox 内)
| 调用 | 延迟 |
|---|---|
| 第 1 次 | 2133 ms(Jupyter kernel 首次交互 + HTTPS 握手) |
| 第 2-5 次 | 59 / 69 / 61 / 76 ms |
热路径下稳定在 60-75 ms 量级。
4 路并发 create
| 单 worker 平均 | 1149 ms |
| wall time | 3054 ms |
| 并行加速比 | 1.51x |
嵌套 VM 下 CPU 竞争明显,裸金属官方给的 50 并发 P95 90 ms 应该能看到好得多的并行度。
隔离性验证
在 sandbox 内跑 id 和 uname -r:
id→uid=0(root)— 沙箱内 rootuname -r→6.6.1199-0009-03_2.0.1— 和宿主 VM 内核(6.6.114-43.oc9)完全不同,说明确实是独立 guest 内核,不是共享 namespace
跟 E2B 的关系
E2B 是目前 Agent 沙箱的事实协议。Cube 直接吃这套:
from e2b_code_interpreter import Sandbox # 原封不动的 E2B SDK
with Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"]) as sb:
sb.run_code("print('hi')")
唯一要改的环境变量:
export E2B_API_URL="http://127.0.0.1:3000" # 指向自己的 CubeAPI
export E2B_API_KEY="dummy" # SDK 要求非空,内容无所谓
如果已经有在 E2B 云上跑的 Agent,迁移成本约等于零。
还有几个坑值得说
坑 5:一键安装的 quickcheck 会"假报失败"
online-install.sh 内嵌 up.sh 在所有服务起来后要跑 30 次 quickcheck.sh(每次间隔 2s = 60s 窗口)。在我的嵌套 VM 里,cubelet 首次启动要读完所有插件配置、建 /data/cubelet 的 shared mount、竞争若干文件锁(Cubelet: mainMutexLock: timeout 是典型现象),首次拉起偶尔会被超时判死。
判断方法:即使 install 脚本退 1,也先手动跑一次 quickcheck.sh:
ONE_CLICK_TOOLBOX_ROOT=/usr/local/services/cubetoolbox \
/usr/local/services/cubetoolbox/scripts/one-click/quickcheck.sh
5/5 都通过 + curl http://127.0.0.1:3000/health 返回 {"status":"ok","sandboxes":0} 就是实装好了。
坑 6:模板创建必须带 --probe
不带 probe 的 template 创建会成功,但 sandbox 里起来之后 CubeProxy 前端是 openresty,用户代码还没 listen 住暴露端口时请求会 502。务必 --probe 49999(对 sandbox-code 镜像就是 jupyter kernel 的健康端口)让 Cubelet 等到 probe 通过再做应用级快照。这样后续所有基于这个模板起的 sandbox 冷启动 → snapshot 恢复 → 立刻可用。
坑 7:模板首次创建在嵌套 VM 里得等 7-8 分钟
解包 OCI 镜像到 ext4 rootfs(8 GiB)+ 首次 microVM 引导 + 应用级 snapshot + 快照验证。第二次(相同 image)快得多,因为 rfs-<fingerprint> 可复用。
适用场景判断
- ✅ 自建 Agent 平台:不想把用户代码或数据走第三方云。
- ✅ RL 训练 / SWE-Bench 类 benchmark:官方带了 mini-rl-training 例子,大规模并行环境开销比 Docker 小。
- ✅ 高密度函数计算:5 MB 内存开销做到真隔离,FaaS 底座可以考虑。
- ❌ 只跑可信代码:Docker 足够,装 Cube 是大炮打蚊子。
- ❌ 纯 ARM 环境:目前只支持 x86_64。
总结
- 定位准确:填了 "E2B 协议兼容 + Firecracker 级隔离 + 开箱即用部署" 这块空白,不是又一个 Docker 皮肤。
- 技术扎实:9.7s 的设备激活开销被应用级快照绕过,冷启动稳定到 900ms(嵌套 VM),核心 BootVm 69ms 与官方数据一致。
- 迁移真·零成本:E2B SDK drop-in 兼容,改一个环境变量就能从 E2B 云切到自建。
- 生产化:一键脚本 + systemd autostart + mkcert 自签证书 + CoreDNS split routing 这一套 b2b 细节做得很完备,不是简单 demo。
- 短板:只支持 x86_64,目前 MicroVM 的 RL 场景支持还比较前期(snapshot rollback 是 coming soon),文档以英文/简中混排居多。
想自己跑一遍,如果有裸金属 Linux + KVM,直接在宿主机上跑 online-install.sh,跳过 dev-env VM 这一层,性能应该能接近官方数字。
链接
- GitHub: https://github.com/TencentCloud/CubeSandbox
- 官方文档: http://docs.cubesandbox.ai/
- 发布 PR: https://www.prnewswire.com/news-releases/tencent-cloud-cube-sandbox-goes-fully-open-source-with-five-major-breakthroughs-enabling-large-scale-agent-deployment-302751501.html
附:VM 镜像复用(2026-04-24 补)
这个 dev-env 的 qcow2 镜像(~58 GB)包含完整状态:
- OpenCloudOS 9 guest OS + 所有 provisioning
- Cube 全部组件(CubeAPI / CubeMaster / Cubelet / CubeProxy)
- MySQL / Redis docker compose 数据
- 拉过的 OCI 镜像 + 已 READY 的 template 都在
/data/cubelet/storage/
下次要用的复用路径(跳过 prepare_image.sh 和 online-install.sh,冷启动到可用 ~30 秒):
cd ~/vibecoding/gpu-bench/CubeSandbox/dev-env
# 1. /dev/kvm 权限(如果 udev 又把 ACL 抹了)
sudo setfacl -m u:$USER:rw /dev/kvm
# 2. 后台启动 VM
sg kvm -c "VM_BACKGROUND=1 VM_MEMORY_MB=16384 VM_CPUS=16 ./run_vm.sh"
# 3. SSH 进去
./login.sh
# 4. (VM 内)拉起 Cube 服务栈
/usr/local/services/cubetoolbox/scripts/one-click/up-with-deps.sh
想让 Cube 服务开机自启
初次 prepare_image.sh 装了 cube-sandbox-oneclick.service 但默认没 enable。永久自启:
# 宿主侧执行,脚本通过 SSH 进 VM 开启 unit
cd ~/vibecoding/gpu-bench/CubeSandbox/dev-env
ASSUME_YES=1 ./cube-autostart.sh enable
之后只要 run_vm.sh 启动 VM,Cube 服务就自动起来,连第 4 步 up-with-deps.sh 都省了。
宿主侧端口回顾(run_vm.sh 固化的)
| 端口映射 | 作用 |
|---|---|
127.0.0.1:10022 → guest:22 | SSH |
127.0.0.1:13000 → guest:3000 | CubeAPI(E2B 协议) ← E2B SDK 指这里 |
127.0.0.1:11080 → guest:80 | CubeProxy HTTP |
127.0.0.1:11443 → guest:443 | CubeProxy HTTPS |
从宿主机调 E2B SDK 只要:E2B_API_URL=http://127.0.0.1:13000。