腾讯云服务器跑通 Cube Sandbox:从 PVM 内核到 65 ms 冷启动的全程实战
腾讯云服务器跑通 Cube Sandbox:从 PVM 内核到 65 ms 冷启动的全程实战
适合第一次想把 Cube Sandbox 真正跑起来的开发者。本文用一台普通腾讯云 CVM(OpenCloudOS 9.4 / 8C16G / 无嵌套虚拟化),从空白系统一路推到
Sandbox.create()65ms 完成、E2B SDK 直接打印 Hello World,全程命令、日志、截图都来自真实复现,无遮挡。关键词:Cube Sandbox · OpenCloudOS 9 · PVM 内核 · E2B 兼容 · AI Agent 沙箱 · MicroVM
0. 这台机器长什么样
先把机器档案摆在前面,方便你拿自己的 CVM 对照:
| 项 | 值 |
|---|---|
| OS | OpenCloudOS 9.4 |
| 默认内核 | 6.6.119-47.8.oc9.x86_64 |
| CPU | AMD EPYC 9K65(8 vCPU) |
| 内存 | 15 GiB |
| 系统盘 | 200 GB XFS |
| 公网 IP | 129.211.223.113 |
| 嵌套虚拟化 | 未开放(/proc/cpuinfo无 vmx / svm,/dev/kvm不存在) |
第一件事永远是先跑一遍核对脚本(脚本是我上一篇文章沉淀下来的cube_preflight.sh,与官方online-install.sh的 preflight 一一对齐),免得你后面踩到坑还以为是自己 yum 配错了:
scpcube_preflight.sh root@129.211.223.113:/root/sshroot@129.211.223.113'bash /root/cube_preflight.sh'实测输出(红=阻断 / 黄=提示 / 绿=通过):
读图三秒看懂:
- ✅ OS / 架构 / Root / 命令 / 内存 15GB /
/是 XFS / 磁盘 193 GB / NetworkManager / 镜像出网 全都过; - ❌ 仅
/dev/kvm不存在(CPU flags 里既没有vmx也没有svm)。
这种"只差一刀"的环境正是 Cube Sandbox 设计的主战场之一—— 普通云服务器没有嵌套虚拟化,靠官方提供的PVM 宿主机内核把 KVM 能力补上来,再走和裸金属一样的一键安装流程。下面我就一步步把这台机器从"差一刀"推到"全绿可用"。
1. 第一步:从 GitHub Releases 下载 PVM 宿主机内核
PVM 内核就是 Cube Sandbox 项目自己维护的一个 Linux 内核 fork,把"普通云上没有 KVM"这件事在内核态解决掉。它只通过 GitHub Releases 单包发布(不走 yum 源),文件大小 575 MB。
直接github.com下载在国内会卡到 100KB/s,先看官方 CNB 镜像:
URL_CNB="https://cnb.cool/CubeSandbox/CubeSandbox/-/releases/download/v0.2.2/kernel-6.6.69_cube.pvm.host.005.x_gb85200d80fa2-1.x86_64.rpm"curl-L-C---retry5--retry-delay3-okernel-pvm.rpm"$URL_CNB"\-w"\n[done] http=%{http_code} size=%{size_download} time=%{time_total}s avg=%{speed_download}B/s\n"sha256sum kernel-pvm.rpm实测输出:
速度比 GitHub 直连快了一个量级:56.9s 跑完 575 MB,平均 10.1 MB/s。sha256校验我也顺手做了 —— 装内核之前一定要做这一步,这是后面所有故事的地基。
找最新版本号的小窍门:
curl -fsSL https://api.github.com/repos/tencentcloud/CubeSandbox/releases/latest | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['tag_name']); [print(a['name']) for a in d['assets']]",文件名带cube.pvm.host的就是宿主机内核。
2. 第二步:装内核 + 改 GRUB + 重启
# 1. 安装内核(--oldpackage 跳过版本对比,避免比已装更老时报错)rpm-ivh--oldpackagekernel-pvm.rpm# 2. grubby 列出所有内核 + 当前默认grubby--info=ALL|grep-E"^kernel|^index|^title"grubby --default-kernel实测:
注意一个很省心的细节:RPM 装完grubby已经自动把 PVM 内核切到index=0,所以官方文档里那条grubby --set-default-index=<index>在 OpenCloudOS 9 上默认可以省掉。
接下来跑官方提供的host_grub_config.sh,它会把 PVM 内核需要的一长串启动参数(elevator=noop、transparent_hugepage=never、kvm.nx_huge_pages=never、pti=off等等)合并到GRUB_CMDLINE_LINUX,并按 key 去重,再grub2-mkconfig一次。我先把脚本下到本地看了一眼内容再跑(74 行纯 bash,不下软件不联网,安全):
curl-fsSLhttps://cnb.cool/CubeSandbox/CubeSandbox/-/git/raw/master/deploy/pvm/grub/host_grub_config.sh\-ohost_grub_config.shcathost_grub_config.sh# 看一眼,确认安全bashhost_grub_config.sh执行结果:
最后reboot。我用一个 SSH 探活循环监控:服务器26 秒就回来了,且uname -r已经是6.6.69-cube.pvm.host.005.x-gb85200d80fa2,主机已成功进入 PVM 内核。
3. 第三步:modprobe kvm_pvm,让 /dev/kvm 出现
进入新内核后还差最后一道:加载kvm_pvm模块。这一步很短但效果"立竿见影":
modprobe kvm_pvm lsmod|grepkvmls-la/dev/kvmecho'kvm_pvm'>/etc/modules-load.d/kvm-pvm.conf# 开机自动加载读图重点:
kvm_pvm49 KB → 拉起kvm1.18 MB → 关联kmem_cache与irqbypass,整条 KVM 模块链路就绪。/dev/kvm真的出现了:crw-rw-rw- 1 root kvm 10, 232 May 22 17:04 /dev/kvm。- 内存仍是 15 GiB,PVM 内核基本不吃内存,这一点很关键。
到这里这台 CVM 在 Cube Sandbox 看来就和一台有 KVM 能力的机器完全等价了。
4. 第四步:一键安装 Cube Sandbox,2 分 25 秒拿到完整服务栈
curl-sLhttps://cnb.cool/CubeSandbox/CubeSandbox/-/git/raw/master/deploy/one-click/online-install.sh\|CUBE_PVM_ENABLE=1MIRROR=cnbashCUBE_PVM_ENABLE=1是给 Cube Sandbox 安装器的暗号 —— 让它在沙箱(guest)端用 PVM 优化版的 vmlinux,否则一旦回退到普通 guest 内核,整个性能预期会大打折扣。
实测整套部署只用了 2 分 25 秒(17:04:51 → 17:07:16)。安装器干的事可以从日志里读出来,简化版如下:
[online-install] downloading cube-sandbox-one-click-46424e7.tar.gz... 438 MB, 平均 10.5 MB/s [one-click-runtime] installed PVM guest kernel as .../cube-kernel-scf/vmlinux [one-click-runtime] starting cube-proxy / cube-sandbox-redis / cube-sandbox-mysql ... [one-click-runtime] cube proxy dns ready via cube-proxy-coredns [one-click-runtime] started network-agent pid=8459 [one-click-runtime] started cubemaster pid=8460 [one-click-runtime] started cube-api pid=8461 [one-click-runtime] started cubelet pid=8462 [quickcheck] 1/5 check network-agent healthz ... OK [quickcheck] 2/5 check network-agent readyz ... OK [quickcheck] 3/5 check cubemaster /notify/health ... OK [quickcheck] 4/5 check cube-api /health ... OK [quickcheck] 5/5 check essential sockets and config ... OK [one-click-runtime] core services ready [one-click-runtime] webui listening on 12088 [one-click] install complete (role=control)装完之后,整台机器的运行时全景如下(这张图我会建议你也保存一份,相当于一张"Cube Sandbox 拓扑速记"):
读图重点:
- 5 个 Docker 容器全部 healthy:
cube-webui(12088)、cube-proxy(80/443)、cube-proxy-coredns、cube-sandbox-redis(6379)、cube-sandbox-mysql(3306)。 - 4 个独立进程:
cube-api(3000) 是 E2B 兼容的 REST 网关、cubemaster(8089) 是调度器、cubelet(9966/9998/9999) 是节点 agent、network-agent(19090) 给 CubeVS 做 eBPF 网络。 /usr/local/bin装入 4 个公开命令:cubemastercli(管模板/沙箱)、cubecli(管节点)、cube-runtime与containerd-shim-cube-rs(containerd Shim v2 集成)。
到这一步,机器已经是一台**“开机即可对外提供 E2B 兼容 API 的 Agent 沙箱节点”**。
5. 第五步:建代码解释器模板(19 秒 READY)
cubemastercli tpl create-from-image\--imagecube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest\--writable-layer-size 1G\--expose-port49999--expose-port49983--probe49999输出立刻给出job_id和template_id:
然后用cubemastercli tpl watch --job-id <id>跟进度,整个模板从 PULLING 到 READY 只用了 19 秒(17:07:35 → 17:07:54),最后tpl list看一眼:
记住这串tpl-90d8079679a2410c8b64c7b0,下一步 Python SDK 会用它。
6. 第六步:装 e2b-code-interpreter,写第一段 Agent 代码
yuminstall-ypython3 python3-pip pip3 configsetglobal.index-url https://mirrors.ustc.edu.cn/pypi/simple pip3installe2b-code-interpreterexportE2B_API_URL="http://127.0.0.1:3000"exportE2B_API_KEY="dummy"exportCUBE_TEMPLATE_ID="tpl-90d8079679a2410c8b64c7b0"exportSSL_CERT_FILE="/root/.local/share/mkcert/rootCA.pem"# 一键脚本生成的 mkcert 根证书第一段 Hello World 我刻意写得"啰嗦一点",在沙箱内打印环境信息、跑一次重计算、再写一个文件验证 IO:
importos,timefrome2b_code_interpreterimportSandbox t0=time.perf_counter()sb=Sandbox.create(template=os.environ["CUBE_TEMPLATE_ID"],timeout=120)print(f"[host] sandbox created in{(time.perf_counter()-t0)*1000:.1f}ms, id={sb.sandbox_id}")res=sb.run_code(""" import platform, sys, os, socket print('hello from cube sandbox') print('python :', sys.version.split()[0]) print('platform :', platform.platform()) print('hostname :', socket.gethostname()) print('cpus :', os.cpu_count()) print('cwd :', os.getcwd()) """)print(res.logs.stdout)跑一次:
几个细节非常值得读:
- 沙箱端到端创建只花了 73.1 ms(从 SDK
Sandbox.create()调用到sandbox_id返回,含网络往返)。 - 沙箱里
uname -r是6.6.69-cube.pvm.guest.005.x-gb85200d80fa2,注意是pvm.guest,和宿主的pvm.host配对 —— 这就是CUBE_PVM_ENABLE=1起的作用。 hostname=tpl-90d8:与模板 ID 前缀一致,便于排查。- 沙箱内
cpus=2是模板默认配置;/sandbox-data/note.txt写入读出一切正常。 listdir /看见的是一个独立的 Linux 根(bin/etc/lib/proc...),不是宿主机的/,这就是"内核级隔离"在文件系统层的直观体现。
7. 第七步:把它当 Agent 用 —— shell + 数据 + 画图 + 多沙箱隔离
光打印 Hello 没什么意思,这一节我用一个稍长的脚本把Cube Sandbox 的几大核心能力一次性跑全:
- 沙箱内执行 shell(
id/uname/df); - 沙箱内
pip install numpy matplotlib; - 沙箱内画 sin/cos 图,写入
/workspace/plot.png; - 用
sb.files.read()把图取回宿主机; - 同时再开两个沙箱,在
sb1写/tmp/secret.txt,验证sb2看不见。
跑一次:
然后是沙箱里画的、宿主机拉回来的那张图:
回看运行结果:
- 三个沙箱依次 65 / 77 / 65 ms冷启动;
- 隔离验证:
sb2 sees /tmp/secret.txt ? False—— 完美隔离; - 沙箱内
df -h /显示overlay2 1.1G正好对应--writable-layer-size 1G; - 沙箱里
pip install成功(走 USTC 镜像)—— 说明 Cube Sandbox 默认给沙箱开了出网(你也可以用 CubeVS 做细粒度网络策略,那是另一个话题)。
如果你做过 E2B 集成会发现:这段代码里完全没出现 Cube 字样。from e2b_code_interpreter import Sandbox+Sandbox.create(...)是原汁原味 E2B SDK 调用,唯一改的就是E2B_API_URL这一个环境变量。这就是官方说的"零成本迁移"。
8. 重头戏:冷启动延迟 benchmark(连开 30 个)
README 上写"60 ms 单并发 / P95 90 ms 50 并发",到底是不是真的?我连续创建了 30 个沙箱:
times_ms=[]foriinrange(30):t0=time.perf_counter()sb=Sandbox.create(template=T,timeout=60)dt=(time.perf_counter()-t0)*1000times_ms.append(dt);print(f"[{i+1:>2}/30]{dt:7.1f}ms")实测:
| 指标 | 实测 | README 官方(参考) |
|---|---|---|
| min | 57.8 ms | - |
| P50 | 65.4 ms | 60 ms(裸金属,单并发) |
| mean | 66.1 ms | 67 ms(裸金属,50 并发) |
| P95 | 78.3 ms | 90 ms(裸金属,50 并发) |
| max | 81.0 ms | - |
这是在普通云 CVM + PVM 这种"二次虚拟化"场景下测出来的数据,P50 65.4 ms、P95 78.3 ms—— 完全配得上 README 里那条"百毫秒级"基线。要知道,30 次连开里没有一次破百,对比 Docker 的 ~200 ms 已经领先 3-5 倍,对比传统 VM(秒级)就是数量级的差距。
回想这个数据是怎么实现的:模板启动时,Cube Sandbox 已经在节点上预先做好了 rootfs 解包、运行时初始化、网络栈准备,一次Sandbox.create实际上是在预热好的资源池里 Clone 一个 MicroVM,这就是 README 里"基于资源池化预置和快照克隆技术,跳过耗时初始化流程"的工程含义。
9. 这台机器现在是什么状态
把上面所有步骤的产物归纳一下:
| 维度 | 之前 | 现在 |
|---|---|---|
| 内核 | 6.6.119-47.8.oc9.x86_64(默认) | 6.6.69-cube.pvm.host.005.x-gb85200d80fa2(PVM 宿主) |
/dev/kvm | 不存在 | crw-rw-rw-已生成 |
| Cube Sandbox 服务 | 未安装 | 5 个 Docker 容器 + 4 个独立进程,5/5 quickcheck 全过 |
cubemastercli tpl list | / | tpl-90d8079679a2410c8b64c7b0STATUS=READY |
e2b-code-interpreter | / | v2.6.2,环境变量已export |
| 一次冷启动 | / | 65 ms 量级(P50 65.4ms) |
| 端口 | / | 80/443 (cube-proxy)、3000 (cube-api)、12088 (webui) 等 |
接下来你可以做什么?几个方向我自己马上会去试:
- 把它接到现有的 LangChain / LangGraph / LlamaIndex Agent:因为是 E2B 兼容,绝大多数 Agent 框架"换一个
E2B_API_URL"就能直接跑你私有部署的 Cube Sandbox,不用重写工具。 - 跑 SWE-Bench 这种基准:README 视频演示里就有 RL + SWE-Bench 场景;这台机器 8C16G + Cube 已经够开 30+ 沙箱并发跑评测。
- 开 CubeVS 网络策略:限制沙箱只能访问白名单域名,这是防"prompt 注入诱导 curl 外泄"的关键一道。
- 打 webui:浏览器开
http://<IP>:12088就能看到沙箱、模板、节点的可视化面板(前提是把 12088 加到安全组)。
10. 写在最后:为什么这条路值得走
在写这篇之前我做了一台 2C2G 机器的"环境核对"练习,结论是:Cube Sandbox 对环境的硬要求其实只有三条——/dev/kvm、内存 ≥ 8GB、/data/cubelet在 XFS 上。前两条把绝大多数普通 CVM 挡在门外,但这并不意味着你必须买裸金属:
- PVM 内核这条路是真的能走通,而且不慢:给一台没有嵌套虚拟化的腾讯云 CVM 装上 PVM 内核 + 一键脚本部署 + 建模板 + 跑通 SDK,全程不到 10 分钟(我从 17:04 开始下载内核,17:18 已经在跑 30 沙箱 benchmark);
- OpenCloudOS 9 是 Cube Sandbox 的"first-class"目标平台:必需命令、文件系统类型、NetworkManager、yum、Docker 一键装 —— 全程零适配;
- 冷启动 65 ms 是真的,不是营销数字,普通 CVM + PVM 都能复现。
如果你是在做 AI Agent / 代码执行 / RL 训练 / E2B 私有化,我会给一个朴素建议:在你的开发环境里先按这篇文章跑通一遍。等你接下来给 Agent 写第二个、第三个工具时,"这段代码能不能放心跑在生产里"这个问题会有一个非常具体的答案——一个 65 ms 起、内核级隔离、E2B 完全兼容、可由你自己审计的 MicroVM。
附录 A:cube_preflight.sh 完整版
与官方
online-install.sh的 preflight 完全对齐,可独立跑,1 秒出结果。
#!/usr/bin/env bashset-uc_red='\033[0;31m';c_grn='\033[0;32m';c_yel='\033[0;33m';c_cyn='\033[0;36m';c_rst='\033[0m'ok(){printf"${c_grn}[ OK ]${c_rst}%s\n""$*";}warn(){printf"${c_yel}[WARN]${c_rst}%s\n""$*";}fail(){printf"${c_red}[FAIL]${c_rst}%s\n""$*";}hd(){printf"\n${c_cyn}== %s ==${c_rst}\n""$*";}hd"1. 操作系统";./etc/os-release2>/dev/null||trueecho" PRETTY_NAME :${PRETTY_NAME:-unknown}"case"${ID:-}"inopencloudos)ok"OpenCloudOS 检测到";;*)warn"非 OpenCloudOS(${ID:-unknown})";;esachd"2. 内核 & 架构";echo" uname -r :$(uname-r)";echo" uname -m :$(uname-m)"[["$(uname-m)"=="x86_64"]]&&ok"x86_64"||fail"需要 x86_64"hd"3. Root 权限"[["${EUID}"-eq0]]&&ok"root"||fail"必须 root"hd"4. 必需命令"forcmdintarawkcurlwgetpython3 systemctl;docommand-v"$cmd">/dev/null&&ok"$cmd->$(command-v"$cmd")"||fail"缺命令:$cmd"donehd"5. KVM 能力(/dev/kvm)"if[[-e/dev/kvm]];thenok"/dev/kvm ->$(ls-l/dev/kvm)"elsefail"/dev/kvm 不存在"flags=$(grep-oE'(vmx|svm)'/proc/cpuinfo|sort-u|tr'\n'' ')[[-n"$flags"]]&&warn"CPU flags:$flags(可能可启用嵌套 KVM)"\||warn"无 vmx/svm flag,必须走 PVM 路径"fihd"6. 内存 (>= 8 GB)"mem_kb=$(awk'/MemTotal/ {print $2}'/proc/meminfo)mem_gb=$(awk-vk="$mem_kb"'BEGIN{printf "%.2f", k/1024/1024}')echo" MemTotal:${mem_kb}KB (~${mem_gb}GB)"[["$mem_kb"-ge7500000]]&&ok"内存达标"||fail"内存不达标(min_mem_kb=7500000 写死)"hd"7. /data/cubelet 所在分区 (要求 XFS)"target=/data/cubelet;probe="$target"while[[!-e"$probe"]];doparent=$(dirname"$probe");[["$parent"=="$probe"]]&&break;probe="$parent";donefs_type=$(df-T"$probe"2>/dev/null|awk'NR==2 {print $2}')echo" 探测路径 :$probe";echo" 文件系统 :${fs_type:-unknown}"[["$fs_type"=="xfs"]]&&ok"XFS"||fail"需要 XFS"hd"8. 磁盘空闲空间"avail_kb=$(df-k/|awk'NR==2 {print $4}')avail_gb=$(awk-vk="$avail_kb"'BEGIN{printf "%.1f", k/1024/1024}')echo" / 可用 :${avail_gb}GB"[["$avail_kb"-ge31457280]]&&ok"充足"||warn"建议预留 30GB+"hd"9. DNS 能力"ifcommand-vresolvectl>/dev/null;thenok"resolvectl 可用"elsestate=$(systemctl show-pLoadState--valueNetworkManager2>/dev/null||echo"?")[["$state"=="loaded"]]&&ok"NetworkManager loaded"||fail"需要 resolvectl 或 NetworkManager"fihd"10. Docker"command-vdocker>/dev/null&&ok"$(docker--version)"||warn"未装 docker(一键脚本会自动装)"hd"11. 网络出网"foruinhttps://cnb.cool https://mirrors.ustc.edu.cn;docode=$(curl-o/dev/null-s-w"%{http_code}"--max-time8"$u"||echo"000")[["$code"=~^[23]]]&&ok"$u-> HTTP$code"||warn"$u-> HTTP$code"donehd"汇总"echo" 本机:${PRETTY_NAME:-?}|$(uname-r)|$(uname-m)| mem${mem_gb}GB | / fs${fs_type:-?}"echo" 时间:$(date'+%F %T %Z')"附录 B:参考链接
- Cube Sandbox GitHub:https://github.com/TencentCloud/CubeSandbox
- Cube Sandbox CNB 镜像:https://cnb.cool/CubeSandbox/CubeSandbox
- 官方文档首页:https://cubesandbox.com/
- PVM 部署文档:https://cubesandbox.com/guide/pvm-deploy.html
- E2B Code Interpreter SDK:https://github.com/e2b-dev/code-interpreter
- OpenCloudOS:https://www.opencloudos.org/
