Cube Sandbox 开发环境实战:在一次性 OpenCloudOS 9 虚拟机中搭建、调试与验证完整沙箱
2026/9/15 12:58:51 网站建设 项目流程

Cube Sandbox 开发环境实战:在一次性 OpenCloudOS 9 虚拟机中搭建、调试与验证完整沙箱

【免费下载链接】CubeSandboxInstant, Concurrent, Secure & Lightweight Sandbox for AI Agents.项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbox

本文讲解 Cube Sandbox 仓库中 dev-env/ 目录提供的一套纯脚本开发环境:它会在宿主机上拉起一台用完即弃的 OpenCloudOS 9 虚拟机,把 SSH 与 Cube API 等端口转发回 localhost,让你在不污染宿主机的条件下端到端体验 Cube Sandbox,并能在修改仓库代码后把新二进制推入虚机、在真实安装里看到改动效果。读完本文,你将掌握镜像预置、虚机启停、一键安装、自启托管、二进制热同步、manual-release 与日志回收的完整工作流,以及每个脚本背后可调的参数。

这套开发环境解决什么问题

Cube Sandbox 本身是一个需要 Kernel-based Virtual Machine(KVM)支持的轻量级沙箱平台:它会在一台 MicroVM 中运行 AI Agent 的代码。如果你在 Linux 笔记本上直接编译、部署、验证,宿主机很容易被各种依赖和服务"污染"。dev-env/目录给出的答案是一组 shell 脚本,用 QEMU/KVM 拉起一台一次性的OpenCloudOS 9虚拟机,并建立如下端口转发:

SSH : 127.0.0.1:10022 -> guest:22 Cube API : 127.0.0.1:13000 -> guest:3000 Cube HTTP: 127.0.0.1:11080 -> guest:80 Cube TLS : 127.0.0.1:11443 -> guest:443 WebUI : 127.0.0.1:12088 -> guest:12088

它面向两类场景:

  • 在 Linux 笔记本上端到端体验 Cube Sandbox,且不污染宿主机
  • 修改本仓库代码后,在真实的 Cube Sandbox 安装里看到改动效果——这才是dev-env/存在的核心价值。

需要明确的是,这不是生产部署方式。生产环境请走 deploy/one-click/ 目录提供的一键部署流程。整个dev-env/设计上就是单节点、密码登录、用完即弃的开发玩具,不要用它承载真实业务。

从源码结构看,dev-env/由 6 个宿主机侧脚本(prepare_image.shrun_vm.shlogin.shcube-autostart.shsync_to_vm.shcopy_logs.sh)和 5 个 guest 内初始化脚本(internal/目录)组成,分工非常清晰。

前置条件与快速自检

在开始之前,请确认宿主机满足以下条件:

  • Linux x86_64(脚本同样支持 aarch64 宿主机,下文会说明)宿主机,已启用 KVM(存在/dev/kvm);
  • 宿主机开启了nested virtualization(嵌套虚拟化)——因为 Cube Sandbox 会在虚机内部再起 MicroVM,guest 里必须也能使用/dev/kvm
  • 宿主机已安装:qemu-system-x86_64qemu-imgcurlsshscpsetsidpython3rg(ripgrep)。

快速自检命令:

ls -l /dev/kvm cat /sys/module/kvm_intel/parameters/nested # AMD 则是 kvm_amd,期望输出 Y / 1

run_vm.sh在启动时会再次强制校验这两点:脚本开头的need_cmd会逐一检查依赖命令(run_vm.sh),若/dev/kvm不存在直接报错退出;require_nested_kvm()会读取/sys/module/kvm_intel/parameters/nestedkvm_amd对应文件(run_vm.sh),只有当值不是Y1时才拒绝启动——这正是为了确保 guest 内还能再起 MicroVM。

快速上手:五步搭建完整开发环境

按顺序执行以下五步即可。

第 1 步:准备虚机镜像(一次性,约 10 分钟)

./prepare_image.sh

该脚本会自动完成:下载 OpenCloudOS 9 云镜像 → 用qemu-img resize把 qcow2 扩到 100G → 通过run_vm.sh后台启动虚机 → 等待 SSH 就绪(默认超时 180 秒,见 prepare_image.sh)→ 依次上传并执行internal/下的初始化脚本 → 请求 guestsudo shutdown -h now优雅关机,得到一块"金镜像"。

guest 内完成的初始化包括:

  • 扩根文件系统internal/grow_rootfs.sh会先qemu-img resize虚拟磁盘,再在 guest 内调用growpart/xfs_growfs(XFS)或resize2fs(ext 系)把根分区与文件系统扩满。脚本还兼容 LVM 根布局(依次走pvresizelvextend -r),并支持在线扩容(grow_rootfs.sh);
  • 放宽 SELinuxinternal/setup_selinux.sh通过setenforce 0+ 改写/etc/selinux/config把 SELinux 切到 permissive,并且是持久化的。脚本注释解释了原因(setup_selinux.sh):OpenCloudOS 9 默认 enforcing,container-selinux会限制容器进程访问 bind mount 进容器的宿主机目录(例如 SQL 初始化目录挂到 mysql 容器的/docker-entrypoint-initdb.d),导致容器反复重启。开发环境里最简单稳妥的解法就是 permissive;
  • 修 PATHinternal/setup_path.sh/etc/profile.d/写入cubesandbox-path.sh,保证每个登录 shell 都有/usr/local/{sbin,bin};同时写入/etc/sudoers.d/00-cubesandbox-path扩展 sudo 的secure_path(默认不含/usr/local/bin,会导致sudo cubemastercli找不到命令),并先用visudo -cf校验再安装,避免语法错误锁死 sudo(setup_path.sh);
  • 安装登录 bannerinternal/setup_banner.sh/etc/profile.d/cubesandbox-banner.sh放置欢迎横幅(setup_banner.sh);
  • 安装 autostart systemd unitinternal/setup_autostart.sh写入cube-sandbox-oneclick.service只安装、不 enable,enable 留给后面的cube-autostart.sh)。

完成之后虚机自动关机。只在首次搭建、或者删掉.workdir/之后再跑一次。

关于 autostart unit,这里值得展开一下:internal/setup_autostart.sh生成的 unit 文件内容如下(setup_autostart.sh):

[Unit] Description=Cube Sandbox one-click bring-up After=docker.service network-online.target Wants=docker.service network-online.target ConditionPathExists=/usr/local/services/cubetoolbox/scripts/one-click/up-with-deps.sh [Service] Type=oneshot RemainAfterExit=yes EnvironmentFile=-/usr/local/services/cubetoolbox/.one-click.env ExecStart=/usr/local/services/cubetoolbox/scripts/one-click/up-with-deps.sh ExecStop=/usr/local/services/cubetoolbox/scripts/one-click/down-with-deps.sh TimeoutStartSec=600 TimeoutStopSec=120 [Install] WantedBy=multi-user.target

ConditionPathExists保证在 guest 内尚未运行 online-install(即 one-click 脚本还没装到/usr/local/services/cubetoolbox)时,该 unit 静默跳过,因此在全新镜像上执行此脚本也是安全的。

第 2 步:启动虚机(终端 A)

./run_vm.sh

QEMU 串口控制台会挂在这个终端里。不要用Ctrl+a然后x直接退出 QEMU(相当于硬断电,可能导致 guest 异常)。正确做法是在另一个终端执行./login.sh登录 guest,在 guest 内执行poweroff正常关机;guest 关机后本终端里的run_vm.sh通常会随之结束。

从源码看(run_vm.sh),QEMU 使用-enable-kvm-machine q35,accel=kvm(x86_64)或virt(aarch64,自动探测 UEFI 固件路径)、-cpu host,并通过 user 模式的-nic hostfwd=tcp:...一次性完成上面那张表里的 5 条端口转发。aarch64 宿主机上,脚本会按 Debian/Ubuntu、Fedora/RHEL/OC9、Arch、openSUSE 的常见路径查找QEMU_EFI.fd等固件(run_vm.sh)。

第 3 步:登录虚机(终端 B)

./login.sh

直接进入 guest 内的 root shell,密码自动处理。login.sh通过生成一个临时SSH_ASKPASS脚本配合setsid -w自动完成密码认证(login.sh),无需预先配置 SSH 密钥;默认以opencloudos用户登录后执行sudo -i切到 root(LOGIN_AS_ROOT=0则保持普通用户身份)。

第 4 步:在虚机内安装 Cube Sandbox(每个新虚机一次)

在第 3 步打开的 guest shell 里执行:

curl -sL https://github.com/tencentcloud/CubeSandbox/raw/master/deploy/one-click/online-install.sh | bash

跑完后应该能看到核心进程都活着(cubemastercube-apicubelet)。需要注意,仓库当前的说明指出:原来的网络运行时已经内置到cubelet——网络组件不再是独立进程,而是随cubelet一起启动,这一点也体现在第 5 步之后 autostart 的描述里。

第 5 步:验证(在虚机里)

curl -sf http://127.0.0.1:3000/health && echo OK

看到OK就表示 Cube Sandbox 已经跑起来了。此时你在宿主机上访问http://127.0.0.1:13000(即 guest 的 3000 端口)、http://127.0.0.1:12088(WebUI)、http://127.0.0.1:11080(CubeProxy HTTP)等,即可通过端口转发体验整套服务。

让虚机重启后服务还在(一次性,强烈推荐)

默认情况下 cube 组件是裸进程拉起的——虚机一重启就不会自动回来。要让 systemd 在每次开机时把它们带回来,在宿主机上跑(在第 5 步之后):

./cube-autostart.sh # 默认子命令:enable

该脚本会先交互确认,然后在 guest 内systemctl enable --now cube-sandbox-oneclick.service(cube-autostart.sh)。之后每次开机都会自动执行 one-click 安装器自带的up-with-deps.sh,把 MySQL/Redis、cube-proxy、coredns、cubemaster、cube-api、cubelet 一并拉起;网络运行时随cubelet一起启动。

其他子命令:

./cube-autostart.sh status # 查看 is-enabled / is-active,并打印完整 systemctl status ./cube-autostart.sh disable # 回退(默认同时停掉当前进程)

开发循环:改代码、推到虚机、看效果

这是dev-env/存在的真正价值所在。推荐的终端分工是:常驻开着一个./login.sh(默认直接进 guest 的 root shell),然后在宿主机终端里做开发循环:

make all ./sync_to_vm.sh bin cubelet cubemaster

关键点:现在的sync_to_vm.sh只有一个职责——把文件拷进虚机。它不会在宿主机构建、不会重启服务、不会跑quickcheck.sh,也不会自动回滚。所有构建动作都要你在宿主机上提前完成(例如make all)。

拷贝结束后,把脚本打印出来的重启命令粘进./login.sh那个终端里:

systemctl restart cube-sandbox-oneclick.service

常用示例:

# 同步 _output/bin/ 里所有已知组件 ./sync_to_vm.sh bin # 只同步指定组件 ./sync_to_vm.sh bin cubemaster cubelet # 推任意文件到 guest ./sync_to_vm.sh files --remote-dir /tmp ./configs/foo.toml # 构建并部署 WebUI 到 guest make -C .. web-sync-dev-env

从源码看(sync_to_vm.sh),bin子命令会把宿主机_output/bin/下的二进制经 scp 传到 guest 的临时路径,再在 guest 内mv到对应安装目录,同时把旧二进制保留为<name>.bakchmod +x。已知组件与 guest 内安装路径的映射关系如下(sync_to_vm.sh):

组件名guest 内安装路径(相对/usr/local/services/cubetoolbox/
cubemaster/cubemastercliCubeMaster/bin/
cubelet/cubecliCubelet/bin/
cube-apiCubeAPI/bin/
cube-runtime/containerd-shim-cube-rscube-shim/bin/(保持 one-click 的/usr/local/bin软链不变)

旧二进制仍然会在 guest 里保留成*.bak,但脚本输出不再主动教你怎么 verify / rollback;需要的话你自己在虚机里处理(把*.bak手动移回去,再systemctl restart)。前置条件:第 4 步已完成;推荐先跑过./cube-autostart.sh

manual-release 流程

需要手工发版验证时,先在宿主机终端里:

make manual-release ./sync_to_vm.sh files \ _output/release/cube-manual-update-*.tar.gz \ deploy/one-click/deploy-manual.sh

然后切到./login.sh的 root 终端里:

bash /tmp/deploy-manual.sh /tmp/cube-manual-update-*.tar.gz

注意sync_to_vm.sh files的默认远端目录是/tmp,所以上面推过去的两个文件会落在 guest 的/tmp/下,脚本提示与示例命令正好对应。这条链路把宿主机make manual-release产出的更新包与 deploy/one-click/deploy-manual.sh 手册升级脚本组合起来,在虚机里验证真实的手动升级流程。

从虚机收日志

./copy_logs.sh

该脚本会在 guest 内把/data/log打包成 tarball(sudo tar -czf,落在 guest/tmp/),再 scp 回宿主机dev-env/目录下,文件名为data-log-<时间戳>.tar.gz(copy_logs.sh),例如data-log-20260915-021500.tar.gz/data/log正是 one-click 部署各组件日志的默认落点,排查问题时可先据此集中回收证据。

常见问题速查表

现象可能原因解决方法
虚机内没有/dev/kvm宿主机未开启 nested KVM在宿主机启用 nested virtualization,再重启虚机
./login.sh连不上虚机还没启动,或宿主机 10022 端口被占用确认./run_vm.sh还在运行,或换SSH_PORT
虚机里df -h /还是很小prepare_image.sh没走完自动扩容查看.workdir/qemu-serial.log,然后把 internal/grow_rootfs.sh scp 进去手动跑一次
宿主机 13000 / 11080 / 11443 / 12088 端口被占本机有别的服务在用这些 dev-env 转发端口CUBE_API_PORT=23000 CUBE_PROXY_HTTP_PORT=21080 CUBE_PROXY_HTTPS_PORT=21443 WEB_UI_PORT=22088 ./run_vm.sh启动
虚机重启后 cube 组件没了还没开启 autostart跑一次./cube-autostart.sh
重启后新二进制不好使新构建有问题,或你手动跑quickcheck失败了看 guest 里/data/log/,必要时把对应的*.bak手动移回去,再重新systemctl restart

关于排查辅助:prepare_image.shrun_vm.sh把工作产物统一放在dev-env/.workdir/下,其中qemu-serial.log记录虚机串口日志。如果 guest 内sshd.service启动失败,prepare_image.shwait_for_ssh()会从串口日志中用rg匹配Failed to start sshd之类关键字提前报错(prepare_image.sh),并把串口日志路径打印出来供人工检查,这是一个很实用的排障入口。

参考:文件清单与环境变量

文件清单

dev-env/ ├── README.md / README_zh.md ├── prepare_image.sh # 第 1 步:下载镜像、扩容、guest 内初始化 ├── run_vm.sh # 第 2 步:QEMU/KVM 启动虚机 + 端口转发 ├── login.sh # 第 3 步:免密自动登录 root shell ├── cube-autostart.sh # enable / disable / status systemd autostart unit ├── sync_to_vm.sh # 只负责把宿主机产物拷进虚机,不 build/不 restart ├── copy_logs.sh # 拉取 /data/log 打包回宿主机 └── internal/ # 由 prepare_image.sh 传进虚机执行 ├── grow_rootfs.sh # 扩根文件系统到 qcow2 虚拟大小(兼容 XFS/ext/LVM) ├── setup_selinux.sh # SELinux 切 permissive(兼容 docker bind mount) ├── setup_path.sh # /usr/local/{sbin,bin} 加入登录 PATH 与 sudo secure_path ├── setup_banner.sh # /etc/profile.d/ 登录 banner └── setup_autostart.sh # 安装 cube-sandbox-oneclick.service(不 enable)

生成的 qcow2 镜像、QEMU pid 文件(qemu.pid)、串口日志(qemu-serial.log)都放在.workdir/下。

环境变量总览

所有脚本都遵循"环境变量覆盖默认值"的设计,下表完整列出各脚本的可调参数。

prepare_image.sh
变量默认值说明
AUTO_BOOT1启动虚机做 guest 内初始化。0跳过(只下载 + 扩容)。
SETUP_AUTOSTART1安装 systemd autostart unit(自动 enable)。0跳过。
IMAGE_URLOpenCloudOS 9 官方云镜像覆盖源 qcow2 URL。
TARGET_SIZE100Gqcow2 最终虚拟大小。
SSH_PORT10022宿主机转发到 guest 22 的端口。

补充两个源码里出现、文档未列的参数,方便需要时使用:AUTO_RESIZE_IN_GUEST(默认10则跳过 guest 内扩根,配合AUTO_BOOT=0时脚本会打印手工 scpgrow_rootfs.sh的提示命令,见 prepare_image.sh);FORCE_KILL_ON_EXIT(默认01时若 QEMU 未随 guest 关机退出则强制 kill)。此外,SSH_WAIT_TIMEOUT_SECS(默认 180)控制等待 SSH 就绪的超时,SHUTDOWN_WAIT_TIMEOUT_SECS(默认 120)控制等待 guest 关机的超时。

run_vm.sh
变量默认值说明
VM_MEMORY_MB8192guest 内存(MB)。
VM_CPUS4guest vCPU 数。
SSH_PORT10022宿主机 → guest SSH。
CUBE_API_PORT13000宿主机 → guest Cube API。
CUBE_PROXY_HTTP_PORT11080宿主机 → guest CubeProxy HTTP(guest:80)。
CUBE_PROXY_HTTPS_PORT11443宿主机 → guest CubeProxy HTTPS(guest:443)。
WEB_UI_PORT12088宿主机 → guest WebUI HTTP(guest:12088)。
REQUIRE_NESTED_KVM1宿主机未开 nested KVM 时拒绝启动。0跳过(沙箱跑不起来)。

补充:TARGET_ARCH默认取uname -marm64自动归一为aarch64),因此同一套脚本也可在 aarch64 宿主机上运行(需要对应架构的 UEFI 固件);VM_BACKGROUND=1可让 QEMU 以 daemonize 方式后台运行并把串口写入qemu-serial.logprepare_image.sh内部正是这么调用的。

login.sh
变量默认值说明
LOGIN_AS_ROOT10保持普通用户(opencloudos)身份,不执行sudo -i
cube-autostart.sh
变量默认值说明
ASSUME_YES01跳过交互确认。
STOP_NOW1disable生效:0只在下次开机不起,不停掉当前进程。
UNIT_NAMEcube-sandbox-oneclick.service覆盖 systemd unit 名。

子命令:enable(默认)、disablestatus,另外支持-h/--help

sync_to_vm.sh
变量默认值说明
UNIT_NAMEcube-sandbox-oneclick.service脚本末尾打印的重启提示里会用到的 unit 名。
OUTPUT_BIN_DIR_output/binbin子命令读取宿主机二进制的目录。

子命令:

  • bin [NAME ...]:把预构建好的二进制推到 guest 对应安装路径;不写NAME时同步全部已知组件(cubemastercubemasterclicubeletcubeclicube-apicube-runtimecontainerd-shim-cube-rs)。
  • files [--remote-dir DIR] PATH [PATH ...]:把任意文件或目录推到 guest(默认远端目录/tmp)。
  • -h--help:查看内置帮助。

补充:TOOLBOX_ROOT(默认/usr/local/services/cubetoolbox)控制 guest 内的安装根目录。

copy_logs.sh
变量默认值说明
REMOTE_LOG_DIR/data/logguest 内要打包的目录。
OUTPUT_DIRdev-env/宿主机上 tarball 的落点。

补充:ARCHIVE_NAME默认data-log-<时间戳>.tar.gzREMOTE_TMP_ARCHIVE默认/tmp/<同名归档>

通用 SSH 覆盖(所有脚本都吃)

所有脚本的 SSH 连接参数统一通过以下四个环境变量覆盖(默认就是上述端口转发的默认值):

VM_USER=opencloudos VM_PASSWORD=opencloudos SSH_HOST=127.0.0.1 SSH_PORT=10022

这套脚本在密码认证上做了自动化处理:每个脚本都会在.workdir/下动态生成一个临时SSH_ASKPASS脚本(内容即明文密码),配合SSH_ASKPASS_REQUIRE=forcesetsid -w触发 OpenSSH 的 askpass 机制,从而免去配置 SSH 密钥的步骤;脚本退出时通过trap cleanup EXIT删除该临时文件。

总结

dev-env/是 Cube Sandbox 开发者迭代源码时的"沙盒中的沙盒":prepare_image.sh产出一块预置好(扩根、SELinux permissive、PATH、banner、autostart unit)的 OpenCloudOS 9 金镜像;run_vm.sh以嵌套 KVM 启动它并把 5 条端口转发回宿主机;cube-autostart.sh让整套服务随虚机开机自启;sync_to_vm.sh以"只拷贝"的极简职责支撑起 make → sync → restart 的开发循环;copy_logs.sh负责集中回收/data/log排障证据。整个流程单节点、密码登录、用完即弃,是端到端验证 Cube Sandbox 行为与代码改动效果的低成本入口,但请务必牢记:它不是生产部署方式,生产请使用 deploy/one-click/。

【免费下载链接】CubeSandboxInstant, Concurrent, Secure & Lightweight Sandbox for AI Agents.项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbox

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询