CubeSandbox 本地开发环境搭建指南:用 QEMU/KVM 跑起可弃置的 OpenCloudOS 9 沙箱开发 VM
【免费下载链接】CubeSandboxInstant, Concurrent, Secure & Lightweight Sandbox for AI Agents.项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbox
本文是 CubeSandbox 官方开发环境(dev-env/)的完整使用指南。它面向只有笔记本电脑或云主机、没有专用裸金属服务器,却想完整体验 Cube Sandbox(在 AI Agent 场景下即时、并发、安全、轻量的沙箱运行时)或想在其上做二次开发的开发者:通过在宿主机上启动一台可弃置的 OpenCloudOS 9 虚拟机,用三步命令就能获得一个与宿主机隔离、内部又具备嵌套 KVM 能力的完整沙箱实验场。读完本文,你将掌握开发 VM 的镜像制备、启动、登录、一键安装、资源调整、自检排障以及"改代码 → 同步进 VM → 重启服务验证"的完整迭代闭环。
适用场景:为什么要用开发 VM
dev-env/目录位于仓库根目录(dev-env),用一组 Shell 脚本把"下载官方镜像 → 制备镜像 → 启动 VM → 自动登录"整个流程串起来。官方文档明确给出它的适用边界:
- 想要一个干净的 OpenCloudOS 9 环境来端到端体验 Cube Sandbox;
- 手头只有带 KVM 与嵌套虚拟化的笔记本电脑或云 VM,而非物理服务器;
- 希望在不污染宿主机的前提下,反复迭代 Cube Sandbox 的源码并看到修改后的真实运行效果。
⚠️ 这不是生产部署方式。官方文档明确声明这是一个development / evaluation(开发/评估)环境,是刻意设计为单节点、密码认证、可弃置的。生产环境请参考 Quick Start 或 Multi-Node Cluster 在裸金属上部署。
需要强调的核心约束:Cube Sandbox 会在 guest 内部再运行一层 KVM MicroVM(沙箱本身就是虚拟机),因此宿主机必须支持嵌套虚拟化,否则 guest 内没有可用的/dev/kvm,沙箱创建必然失败。
前置条件与宿主机要求
官方文档要求脚本运行在以下三种宿主机之一:
- Windows 上的 WSL 2(要求 Windows 11 22H2+ 且开启 WSL 嵌套虚拟化);
- 一台 Linux 物理机;
- 一台开启了嵌套虚拟化的 Linux VM(云主机或本地 VM 均可)。
三种情况共同的前提是宿主机能用 KVM——/dev/kvm必须存在且可读写。
宿主机需要安装的软件依赖如下:
| 依赖 | 说明 |
|---|---|
| Linux x86_64 或 aarch64 (ARM64) | 且 KVM 已启用(/dev/kvm存在) |
| 嵌套虚拟化 | 必须在宿主机开启 |
qemu-system-x86_64(ARM64 为qemu-system-aarch64)、qemu-img | QEMU 与磁盘工具 |
curl、ssh、scp、setsid | 下载镜像、自动化 SSH 登录 |
| EDK2/AAVMF 固件(仅 aarch64) | ARM64 上 VM 以 QEMUvirt机型 + UEFI 固件启动,需安装QEMU_EFI.fd(如qemu-efi-aarch64包) |
从源码看,run_vm.sh 会自动探测宿主机架构(TARGET_ARCH默认取uname -m,必要时可用环境变量覆盖);在 aarch64 上它会依次在多个发行版路径中查找 UEFI 固件(Debian/Ubuntu 的/usr/share/qemu-efi-aarch64/QEMU_EFI.fd、Fedora/RHEL/OC9 的/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw等),找不到时给出明确的安装提示。
快速开始:三步启动开发 VM
克隆仓库并进入dev-env/:
git clone https://gitcode.com/GitHub_Trending/cu/CubeSandbox cd CubeSandbox/dev-env总共三个命令:前两个在同一个终端执行,第三个需要另开一个终端。
Step 1:制备镜像(一次性)
./prepare_image.sh该脚本从腾讯镜像站下载官方 OpenCloudOS 9 qcow2,并执行初始化。每份全新镜像只需运行一次——除非你删除了生成的.workdir/目录,才需要重新执行。
从源码看,prepare_image.sh 的流程是:检查镜像是否已缓存 → 用qemu-img resize将 qcow2 就地扩容到默认 100G → 以后台模式调用run_vm.sh启动 VM → 通过 SSH(借助SSH_ASKPASS自动填充默认密码)依次上传并执行 guest 内的初始化脚本 → 最后优雅关机,产出一份"金镜像"。
Step 2:启动 VM
./run_vm.shQEMU 串行控制台会挂接在当前终端上。注意不要用Ctrl+a再按x强行退出 QEMU——这种粗暴退出可能损坏 guest。正确做法是另开终端用./login.sh登录,在 guest 内执行poweroff。
源码层面,run_vm.sh 在 x86_64 上使用 q35 机型、aarch64 上使用 virt 机型,均以-enable-kvm -cpu host直通宿主机 CPU,并通过 QEMU 用户态网络的hostfwd一次性建立 5 组端口转发。
Step 3:登录(新终端)
./login.shlogin.sh以 root 身份登录 VM——Cube Sandbox 的安装器要求 root 权限。从源码看,login.sh 通过setsid+SSH_ASKPASS自动完成密码认证(无需提前配置 SSH 密钥),默认执行sudo -i切换到 root shell,可用LOGIN_AS_ROOT=0保留普通用户身份。
在 VM 内安装 Cube Sandbox
进入 root shell 后,运行标准的一键安装器:
curl -sL https://github.com/tencentcloud/CubeSandbox/raw/master/deploy/one-click/online-install.sh | bash::: tip 中国大陆使用腾讯云镜像加速
curl -sL https://cnb.cool/CubeSandbox/CubeSandbox/-/git/raw/master/deploy/one-click/online-install.sh | MIRROR=cn bash:::
安装完成后,按官方 Quick Start 的指引在 VM 中创建模板并运行你的第一个沙箱。安装完成的标志是核心进程存活:cubemaster、cube-api、cubelet(旧的独立网络运行时现已嵌入cubelet);可在 VM 内执行curl -sf http://127.0.0.1:3000/health && echo OK验证。
dev-env 中的 cubecow 存储
Cubelet 默认使用仅依赖 reflink 的cubecow存储后端。开发 VM不需要 LVM/dm-thin 工具或额外裸盘,只需data_path指向的路径位于支持 reflink 的文件系统上(例如以-m reflink=1挂载的 XFS,或 Btrfs)。文档说明:默认的[plugins."io.cubelet.internal.v1.storage".cow.*]配置会在<data_path>/../cubecow-reflink下创建 reflink 卷。
对照仓库中的实际配置,Cubelet/config/config.toml 中可以看到storage_backend = "cubecow"与data_path = "/data/cubelet/storage"的默认值,其注释同时指出 cubecow 的 reflink 卷落在<data_path>/xfs/objects(要求底层文件系统支持 FICLONE)。从源码结构还可以推断:cubecow-reflink是重构前遗留的 reflink 池目录名(见 Cubelet/storage/s3_snapshot_layout.go 的legacyReflinkDirName与 Cubelet/storage/legacy_reflink_cleanup.go 的清理逻辑),新版本对象存放在xfs/objects下。因此如果你在 VM 中看到cubecow-reflink目录,不必惊慌——它是兼容旧数据的布局,开发场景下关键在于data_path所在文件系统必须支持 reflink。
宿主机自检:确认 KVM 与嵌套虚拟化
先做快速健康检查:
ls -l /dev/kvm # Intel cat /sys/module/kvm_intel/parameters/nested # AMD cat /sys/module/kvm_amd/parameters/nested如果nested参数读出来是N或0,需要先在宿主机开启嵌套虚拟化。Intel 示例:
echo 'options kvm_intel nested=1' | sudo tee /etc/modprobe.d/kvm.conf sudo modprobe -r kvm_intel && sudo modprobe kvm_intel从源码看,run_vm.sh 在启动前会强制校验:只要REQUIRE_NESTED_KVM=1(默认),若嵌套参数不是Y/1就直接报错退出——除非显式设置REQUIRE_NESTED_KVM=0(此时 OS 能启动但沙箱无法运行)。
宿主机 ↔ guest 端口映射
run_vm.sh会自动配置以下转发(源码见 run_vm.sh 的hostfwd参数):
| 宿主机 | Guest | 用途 |
|---|---|---|
127.0.0.1:10022 | :22 | SSH 登录开发 VM |
127.0.0.1:13000 | :3000 | Cube Sandbox E2B 兼容 API |
127.0.0.1:11080 | :80 | CubeProxy HTTP |
127.0.0.1:11443 | :443 | CubeProxy HTTPS |
127.0.0.1:12088 | :12088 | WebUI HTTP |
其中 SSH 与 Cube API 两组是官方开发环境文档明确列出的,后三组(CubeProxy/WebUI)可在 dev-env/README.md 与 run_vm.sh 的头部注释中确认。默认资源配置为 4 vCPU、8192 MB 内存。
prepare_image.sh 在 guest 内部做了什么
官方文档把镜像制备的 guest 内动作归纳为四项,每项都能在dev-env/internal/下找到对应脚本:
- 扩容根分区与文件系统,占满整块 100 GB 虚拟盘。实现见 internal/grow_rootfs.sh:脚本先用
findmnt/lsblk定位根设备与文件系统类型,若根在 LVM 上则走pvresize+lvextend -r -l +100%FREE;普通分区则用growpart扩分区、再按文件系统类型调用xfs_growfs /(XFS 在线扩容)或resize2fs(ext 系列),对NOCHANGE情况有专门容错。 - 将 SELinux 切换为 permissive(运行时 + 持久化到
/etc/selinux/config)。原因在 internal/setup_selinux.sh 的注释中写得很清楚:Cube Sandbox 的 MySQL 容器把宿主目录 bind-mount 到/docker-entrypoint-initdb.d,在 enforcing 模式下容器进程会被container-selinux策略拒绝(Permission denied),导致 MySQL 反复重启;开发环境是"可弃置"的,所以最稳的办法就是切到 permissive。 - 确保
/usr/local/{sbin,bin}同时在登录 PATH 和 sudo 的secure_path中。实现见 internal/setup_path.sh:前者通过写入/etc/profile.d/cubesandbox-path.sh实现;后者生成/etc/sudoers.d/00-cubesandbox-path,且在安装前先执行visudo -cf校验语法,避免因 sudoers 语法错误把 sudo 锁死。 - 安装欢迎横幅
/etc/profile.d/cubesandbox-banner.sh。见 internal/setup_banner.sh,每次登录 shell 都会显示Welcome to the Cube Sandbox development environment!以及 guest 内 Cube API 地址等提示。
此外,当SETUP_AUTOSTART=1(默认)时,prepare_image.sh 还会通过 internal/setup_autostart.sh 在 guest 内安装cube-sandbox-oneclick.service这个 systemd 单元(借助ConditionPathExists在未安装一键脚本时静默空转),但不会 enable——启用是后续的显式动作。
常用覆盖变量(环境变量)
三个脚本都支持环境变量覆盖(源码中的默认值可在各脚本头部确认):
# 仅下载 + 扩容,跳过 guest 内自动初始化流程 AUTO_BOOT=0 ./prepare_image.sh # 分配更多资源,或更换转发的 Cube API 端口 VM_MEMORY_MB=16384 VM_CPUS=8 CUBE_API_PORT=23000 ./run_vm.sh # 不要求嵌套 KVM 也能启动(OS 可启动但沙箱跑不起来) REQUIRE_NESTED_KVM=0 ./run_vm.sh # 以普通用户而非 root 登录 LOGIN_AS_ROOT=0 ./login.sh各变量默认值汇总如下(结合官方文档与 dev-env/README.md):
| 脚本 | 变量 | 默认值 | 说明 |
|---|---|---|---|
| prepare_image.sh | AUTO_BOOT | 1 | 是否自动启动 VM 执行 guest 内初始化 |
SETUP_AUTOSTART | 1 | 是否安装自启 systemd 单元(仍不启用) | |
IMAGE_URL | OpenCloudOS 9 官方镜像 | 覆盖镜像源地址 | |
TARGET_SIZE | 100G | qcow2 虚拟磁盘最终大小 | |
SSH_PORT | 10022 | 宿主机转发到 guest 22 的端口 | |
| run_vm.sh | VM_MEMORY_MB/VM_CPUS | 8192/4 | guest 内存与 vCPU |
SSH_PORT | 10022 | SSH 转发 | |
CUBE_API_PORT | 13000 | Cube API 转发(guest:3000) | |
CUBE_PROXY_HTTP_PORT/CUBE_PROXY_HTTPS_PORT | 11080/11443 | CubeProxy HTTP/HTTPS 转发 | |
WEB_UI_PORT | 12088 | WebUI 转发 | |
REQUIRE_NESTED_KVM | 1 | 嵌套 KVM 关闭时拒绝启动;0跳过 | |
| login.sh | LOGIN_AS_ROOT | 1 | 0保持普通用户身份 |
让 Cube Sandbox 开机自启(可选但强烈建议)
默认情况下,guest 内的一键栈是以裸进程方式启动的,VM 重启后不会自动恢复。若要 systemd 在每次开机时拉起整套组件,请在宿主机上执行:
./cube-autostart.sh # 默认子命令:enable脚本会请求确认,然后在 guest 内启用cube-sandbox-oneclick.service(实现见 cube-autostart.sh,它通过 SSH 远程执行systemctl enable --now)。此后每次开机都会运行up-with-deps.sh,把 MySQL/Redis、cube-proxy、coredns、cubemaster、cube-api、cubelet 一起拉起。其它子命令:
./cube-autostart.sh status # 查看 is-enabled / is-active ./cube-autostart.sh disable # 回滚(STOP_NOW=0 可只禁用不停止)开发迭代闭环:改代码 → 同步 → 重启验证
这是dev-env/存在的核心价值,流程在 dev-env/README.md 中有完整说明:
- 保持一个
./login.sh的 root shell 常开; - 在宿主机 shell 中构建并同步二进制:
make all ./sync_to_vm.sh bin cubelet cubemastersync_to_vm.sh现在只负责拷贝文件进 VM,不再负责构建、重启、回滚。它支持bin [NAME ...](同步_output/bin下的已知组件,省略 NAME 则全量)与files [--remote-dir DIR] PATH ...(推送任意文件)两种模式; - 把脚本打印的重启命令粘贴进
./login.sh会话:systemctl restart cube-sandbox-oneclick.service - 故障时用
./copy_logs.sh把 guest 内/data/log打成data-log-<时间戳>.tar.gz拉到宿主机排查。旧二进制在 VM 中保留为*.bak,必要时可手动回退。
推送 WebUI 可用make -C .. web-sync-dev-env;手动发版流程为make manual-release后用sync_to_vm.sh files上传发布包,再在 guest 内执行bash /tmp/deploy-manual.sh /tmp/cube-manual-update-*.tar.gz。
重置与清理
- 重置 VM 状态:停止正在运行的
run_vm.sh,删除dev-env/.workdir/,再执行一次./prepare_image.sh; - 开发 VM 刻意设计为可弃置:每当已安装状态变得不可用时,直接重建即可。生成的 qcow2、QEMU PID 文件、串行日志都位于
.workdir/下。
故障排查速查表
| 症状 | 可能原因 | 修复方法 |
|---|---|---|
guest 内没有/dev/kvm | 宿主机未开启嵌套 KVM | 在宿主机开启嵌套虚拟化并重启 VM |
./login.sh连不上 | VM 未启动完成,或宿主机 10022 端口被占用 | 确认./run_vm.sh仍在运行;或改用SSH_PORT |
cube-sandbox-mysql反复重启且报Permission denied | guest SELinux 仍为 enforcing | 重跑./prepare_image.sh;或在 guest 内:setenforce 0 && sed -i 's/^SELINUX=enforcing/SELINUX=permissive/' /etc/selinux/config && docker restart cube-sandbox-mysql |
guest 内df -h /依旧很小 | 自动扩容步骤未完成 | 检查.workdir/qemu-serial.log,然后将internal/grow_rootfs.shscp 进 guest 手动执行 |
| 宿主机 13000 端口被占用 | 其它服务占用了转发端口 | 使用CUBE_API_PORT=23000 ./run_vm.sh,并同步更新E2B_API_URL;若 11080/11443/12088 同样冲突,可一并覆盖 |
| VM 重启后组件消失 | 未启用自启单元 | 执行一次./cube-autostart.sh |
| 同步新二进制后重启失败 | 新构建有问题 | 查看 guest 内/data/log/;必要时手动恢复*.bak旧二进制后再重启 |
目录布局速览
dev-env/ ├── prepare_image.sh # 一次性:下载 + 扩容 + guest 侧初始化 ├── run_vm.sh # 日常:启动 VM ├── login.sh # 日常:SSH 登录并切换 root ├── cube-autostart.sh # 启用/停用/查看 guest 内自启单元 ├── sync_to_vm.sh # 把宿主机产物同步进 guest(不构建不重启) ├── copy_logs.sh # 拉取 guest 内 /data/log 日志归档 ├── internal/ # 由 prepare_image.sh 在 guest 内调用的辅助脚本 │ ├── grow_rootfs.sh # 扩容根文件系统至 qcow2 虚拟大小 │ ├── setup_selinux.sh # SELinux 切 permissive(Docker bind-mount 兼容) │ ├── setup_path.sh # PATH 与 sudo secure_path 修正 │ ├── setup_banner.sh # /etc/profile.d/ 登录横幅 │ └── setup_autostart.sh # 安装 cube-sandbox-oneclick.service(不启用) ├── README.md └── README_zh.md整套脚本的简短总览可进一步阅读仓库中的 dev-env/README.md。需要再次强调的是:这个环境是单节点、密码认证、可弃置的开发/评估用途,请勿在其中承载真实业务负载。
【免费下载链接】CubeSandboxInstant, Concurrent, Secure & Lightweight Sandbox for AI Agents.项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考