Cube Sandbox Skill 实战指南:用 E2B 兼容 API 为 AI Agent 打造隔离代码执行沙箱
【免费下载链接】CubeSandboxInstant, Concurrent, Secure & Lightweight Sandbox for AI Agents.项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbox
本篇技术指南围绕 Cube Sandbox 仓库中cube-sandboxSkill 文档展开,系统讲解如何通过一套兼容 E2B SDK 的 Python 接口,让 AI Agent 在隔离的 KVM MicroVM 中安全执行 Python 代码、Shell 命令、读写文件、挂载宿主机目录并精细化控制网络策略。读完本文,你将掌握从环境变量配置、SDK 安装到沙箱创建、暂停恢复、问题排查的完整链路,并理解其背后 CubeAPI 路由与 CubeMaster 校验的底层实现。
1. Skill 概览:一次编写,处处隔离
cube-sandbox是 Cube Sandbox 为 AI Agent 提供的安全沙箱执行技能,定义于 examples/openclaw-integration/skills/cube-sandbox/SKILL.md。其核心设计思想是:控制面与数据面完全兼容 E2B SDK,Agent 侧只需修改E2B_API_URL环境变量指向 Cube 部署地址,即可在不改动业务代码的前提下,获得一个隔离的代码执行环境。
从 examples/openclaw-integration/README_zh.md 可以看到完整调用链:
OpenClaw Agent │ cube-sandbox skill ▼ E2B SDK(Python) │ REST API ▼ CubeAPI(端口 3000) │ ▼ CubeMaster ──► Cubelet ──► KVM MicroVM │ cube-agent(PID 1) │ 沙箱化代码Skill 适用的典型场景包括:用户要求"在沙箱中执行代码""跑一段 Python""安全执行""隔离环境运行";执行可能有副作用的代码(文件操作、网络请求、安装包等);读写沙箱内文件、挂载宿主机目录;控制沙箱网络策略(完全断网、白名单、黑名单);以及暂停/恢复沙箱以保留内存快照实现快速复用。
2. 环境配置
2.1 必需环境变量
运行任何沙箱代码前,必须设置以下三个环境变量(可写入.env或~/.bashrc):
export CUBE_TEMPLATE_ID=<模板ID> # 沙箱镜像模板,必填 export E2B_API_URL=http://<host>:3000 # Cube API 地址(用于创建沙箱),必填 export E2B_API_KEY=e2b_000000 # SDK 非空校验用,填任意字符串三者的分工非常明确:
| 变量 | 必填 | 作用 |
|---|---|---|
CUBE_TEMPLATE_ID | ✅ | 沙箱镜像模板 ID,由cubemastercli tpl create-from-image创建后返回 |
E2B_API_URL | ✅ | Cube API Server 地址(默认端口3000),SDK 通过HTTP请求它来创建沙箱 |
E2B_API_KEY | ✅ | 任意非空字符串,仅用于通过 SDK 的非空校验 |
这里有一条关键的网络拓扑事实需要牢记:创建沙箱的流量(E2B_API_URL)与运行代码的流量(沙箱 domain)走的是两条不同路径。E2B_API_URL指向 Cube API Server(端口 3000),此流量不经过CubeProxy;而沙箱创建成功后,SDK 会拿到沙箱返回的 domain(格式如49999-{sandboxID}.cube.app),后续执行代码、读写文件则通过该 domain 访问 CubeProxy(宿主机 443/80 端口)。这一点在 examples/openclaw-integration/README_zh.md 中被反复强调。
2.2 SSL 证书配置(按需)
SSL_CERT_FILE仅在使用 Cube 内置cube.app测试证书时需要配置。CubeProxy 同时提供 HTTPS(宿主机 443)和 HTTP(宿主机 80)两种访问方式:
- E2B SDK(默认走 HTTPS):Cube 已内置 DNS 服务并预装了
cube.app测试证书,开箱即用 HTTPS,无需额外配置证书。如果部署机器使用 mkcert 生成证书,证书通常位于以下位置:
export SSL_CERT_FILE=/root/.local/share/mkcert/rootCA.pem或者指定自定义证书路径:
export SSL_CERT_FILE=/path/to/your/rootCA.pem- 直接 HTTP 访问(不使用 SDK):可通过 HTTP 直接请求沙箱服务,无需证书。请求时
Host头部须符合格式:<sandbox-service-port>-<sandboxId>-<domain>,例如Host: 49999-abc123def456-cube.app。 - 如果使用自定义受信任域名,或通过 HTTP 访问沙箱,可跳过
SSL_CERT_FILE配置。
仅测试时可禁用证书校验(不推荐生产环境),在 Python 代码中添加:
import ssl import warnings warnings.filterwarnings('ignore') ssl._create_default_https_context = ssl._create_unverified_context2.3 安装 Python 和 SDK
第一步:安装 Python 3(如未安装)
# Ubuntu / Debian sudo apt-get update && sudo apt-get install -y python3 python3-pip python3-venv # macOS(使用 Homebrew) brew install python3第二步:安装 e2b-code-interpreter
直接安装:
pip3 install e2b-code-interpreter如果系统提示必须使用 venv(常见于 Ubuntu 22.04+、macOS Homebrew 环境):
python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install e2b-code-interpreter使用 venv 后,后续所有
python/pip命令都需在激活 venv 的终端中执行,或用.venv/bin/python直接调用。
2.4 完整配置示例
# 必需配置 export CUBE_TEMPLATE_ID="tpl-4cc15c28f7a04115a295c159" export E2B_API_URL="http://127.0.0.1:3000" export E2B_API_KEY="e2b_000000" # 使用 cube.app 测试证书时才需要配置(自定义受信任域名或 HTTP 访问可不填) export SSL_CERT_FILE="/Users/username/Downloads/rootCA.pem" # 或 # export SSL_CERT_FILE=/root/.local/share/mkcert/rootCA.pem2.5 重要说明汇总
- 网络访问方式:CubeProxy 同时提供 HTTPS(宿主机 443)和 HTTP(宿主机 80)两种访问方式。
- 创建沙箱:使用 HTTP 访问
E2B_API_URL指定的 Cube API Server 地址(默认端口3000),此流量不经过CubeProxy。 - SSL_CERT_FILE:仅在使用 Cube 内置
cube.app测试证书时需要配置,指向对应 CA 根证书。 - 域名解析:SDK 需要能解析沙箱返回的 domain。Cube 已内置 DNS 服务,默认 domain 为
cube.app,也可通过CUBE_API_SANDBOX_DOMAIN自定义。
3. 核心用法
3.1 执行 Python 代码
import os import ssl import warnings # 方式一:配置证书路径(推荐) os.environ['SSL_CERT_FILE'] = '/path/to/rootCA.pem' # 方式二:禁用证书校验(仅测试) # warnings.filterwarnings('ignore') # ssl._create_default_https_context = ssl._create_unverified_context from e2b_code_interpreter import Sandbox with Sandbox.create(template=os.environ['CUBE_TEMPLATE_ID']) as sb: result = sb.run_code("print('hello cube')") print(result)run_code返回的result对象包含四类关键字段(详见 examples/openclaw-integration/skills/cube-sandbox/references/api.md):
result.stdout # 标准输出列表 result.stderr # 标准错误列表 result.error # 执行异常(None 表示成功) result.results # 富文本输出(图表、HTML 等)从源码角度看,Sandbox.create()最终会向 CubeAPI 发起POST /sandboxes请求。在 CubeAPI/src/routes.rs 中,build_sandbox_routes将POST /sandboxes映射到sandboxes::create_sandboxhandler;而 CubeAPI/src/handlers/sandboxes.rs 中的create_sandbox会记录api.request与sandbox.created两类日志事件,再委托state.services.sandboxes.create_sandbox(body)完成真正的创建,成功后返回201 Created。
3.2 执行 Shell 命令
import os import ssl import warnings # 配置 SSL(选择一种方式) os.environ['SSL_CERT_FILE'] = '/path/to/rootCA.pem' # 或禁用校验(仅测试) # warnings.filterwarnings('ignore') # ssl._create_default_https_context = ssl._create_unverified_context from e2b_code_interpreter import Sandbox with Sandbox.create(template=os.environ['CUBE_TEMPLATE_ID']) as sb: r = sb.commands.run("echo hello") print(r.stdout)3.3 读写沙箱文件
with Sandbox.create(template=template_id) as sb: content = sb.files.read("/etc/hosts") sb.files.write("/tmp/out.txt", "hello")3.4 挂载宿主机目录
宿主机目录挂载是 Cube Sandbox 对标准 E2B API 的扩展能力,通过Sandbox.create()的metadata字段(键名为host-mount)请求:
import json with Sandbox.create(template=template_id, metadata={ "host-mount": json.dumps([ {"hostPath": "/tmp/data", "mountPath": "/mnt/data", "readOnly": False} ]) }) as sb: ...挂载描述符(Mount Descriptor)的完整 schema 如下:
[ { "hostPath": "/absolute/path/on/host", "mountPath": "/path/inside/sandbox", "readOnly": false } ]| 字段 | 类型 | 说明 |
|---|---|---|
hostPath | string | Cubelet 节点上的绝对路径(注意:是运行沙箱的 Cubelet 节点,而非脚本所在机器) |
mountPath | string | 沙箱 VM 内部的目标路径 |
readOnly | bool | true= 只读;false= 可读写 |
安全限制:出于安全考虑,hostPath必须位于允许的前缀(allowed prefixes)之下,默认仅允许/data/shared/。试图挂载前缀之外的路径(如/etc、/var)会被拒绝。该前缀在 CubeMaster 的 YAML 配置中定义(详见 examples/host-mount/README.md):
extra_conf: allowed_host_mount_prefixes: - "/data/shared/" - "/data/team-assets/" # add more as needed配置要点:列表为空或省略时使用默认值["/data/shared/"];根路径/被显式禁止,会导致 CubeMaster 启动时拒绝该配置;路径穿越尝试(如/data/shared/../etc)会先被规范化再检查,同样会被拒绝。若指定了不允许的hostPath,沙箱创建将失败,Python SDK 会抛出ApiError异常(HTTP 400),错误信息形如CubeMaster returned error code 130400: "host-mount" entry[0]: hostPath "/etc/passwd" is not within an allowed mount prefix。
完整的挂载执行链路是:Sandbox.create(metadata=...)→ CubeAPI 将metadata["host-mount"]提升为同名 sandbox annotation → CubeMaster 解析挂载列表并校验hostPath前缀,向 sandbox spec 注入 volumes/volume-mounts → Cubelet 在启动 VM 前 bind-mount 每个已校验路径 → VM 启动后路径出现在沙箱内的mountPath处。只读挂载由内核以MS_RDONLY强制保证,写入会返回EROFS。
注意:Cubelet 直接 bind-mount 源路径且不会自动创建目录,因此挂载前宿主机目录必须已存在,否则沙箱创建会失败。
3.5 网络策略
Cube Sandbox 支持三种出网控制模式:
# 完全断网 Sandbox.create(template=template_id, allow_internet_access=False) # 白名单(只允许指定 CIDR) Sandbox.create(template=template_id, allow_internet_access=False, network={"allow_out": ["10.0.0.0/8"]}) # 黑名单(屏蔽指定 CIDR,其余放行) Sandbox.create(template=template_id, network={"deny_out": ["192.168.1.0/24"]})三种模式的语义对照(结合 examples/network-policy/README.md 中的示例脚本):
| 模式 | 参数组合 | 语义 | 验证方式 |
|---|---|---|---|
| 完全断网 | allow_internet_access=False | 禁止一切出网 | curl -s --max-time 3 https://8.8.8.8 \|\| echo blocked |
| 出口白名单 | allow_internet_access=False+network={"allow_out": [...]} | 仅允许指定 CIDR 出网 | 白名单内可达,其余unreachable |
| 出口黑名单 | network={"deny_out": [...]} | 屏蔽指定 CIDR,其余放行 | 黑名单内被 block,其余可达 |
此外,网络策略支持在沙箱运行期间动态更新:sandbox.update_network(network={"allow_out": ["8.8.8.8/32"], "allow_internet_access": False})可在任务中途收紧或放开策略。从 CubeAPI/src/routes.rs 可以看到,PUT /sandboxes/:sandboxID/network路由专门服务于该能力。
3.6 暂停与恢复
with Sandbox.create(template=template_id) as sb: sb.pause() # 保存内存快照,释放计算资源 sb.connect() # 恢复快照,继续执行 print(sb.get_info())暂停/恢复的价值在于有状态复用:pause()保存沙箱的内存快照并释放计算资源,connect()从快照恢复,继续之前的执行状态,适合需要长时间保留运行上下文的 Agent 任务。
从源码看,这是 CubeAPI 中一条独立的生命周期通道:在 CubeAPI/src/routes.rs 中,POST /sandboxes/:sandboxID/pause、POST /sandboxes/:sandboxID/resume、POST /sandboxes/:sandboxID/connect被单独挂载到pause_resume_router,使用120 秒的超时预算(PAUSE_RESUME_ROUTE_TIMEOUT),因为 pause/resume/connect 共用 Master↔Cubelet 的暂停预算(pauseCubeletRPCTimeout= 120s),远大于默认 30 秒的标准路由超时。这也解释了为什么在常见问题中,删除处于暂停态的沙箱可能返回 503(携带Retry-After头)或 409——内部恢复未完成或节点容量不足时,服务端会给出明确的业务错误码(见 CubeAPI/src/handlers/sandboxes.rs 中kill_sandbox的响应定义)。
4. 使用流程
将上述能力串起来,一次完整的沙箱使用遵循六个步骤:
- 配置环境变量(必填):
CUBE_TEMPLATE_ID(沙箱模板 ID)、E2B_API_URL(HTTP API 地址,如http://127.0.0.1:3000)、E2B_API_KEY(任意字符串,SDK 校验用)。 - 配置 SSL 证书(按需):使用 Cube 内置
cube.app测试证书时,设置SSL_CERT_FILE指向 CA 根证书路径;使用自定义受信任域名或通过 HTTP 访问沙箱时无需配置;测试时也可在代码中禁用证书校验(不推荐生产环境)。 - 创建沙箱:SDK 使用 HTTP 访问
E2B_API_URL创建沙箱,创建成功后返回 sandbox 信息(包含sandbox_id与domain)。 - 执行代码:SDK 自动使用 HTTPS 访问沙箱 domain(如
49938-{sandboxID}.cube.app),确保网络能够解析沙箱的 domain。 - 清理资源:使用
with Sandbox.create(...) as sb:确保沙箱用完自动销毁;或手动调用sandbox.kill()。 - 处理结果:捕获
result.stdout、result.stderr、result.error处理执行结果;需要复用沙箱状态时,使用pause()+connect()而非重新创建。
5. API 参考:从 SDK 到 REST 的完整映射
SKILL 文档所封装的 E2B 能力,底层对应 CubeAPI 的 REST 接口(详见 examples/openclaw-integration/skills/cube-sandbox/references/api.md 与 CubeAPI/src/routes.rs):
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /health | 健康检查(无需认证) |
| GET | /sandboxes | 列出所有 sandbox(v1) |
| GET | /v2/sandboxes | 列出 sandbox(v2,支持 state/metadata 过滤、limit) |
| POST | /sandboxes | 创建 sandbox |
| GET | /sandboxes/:id | 查询单个 sandbox 详情 |
| DELETE | /sandboxes/:id | 销毁 sandbox |
| POST | /sandboxes/:id/pause | 暂停 sandbox(保留内存快照) |
| POST | /sandboxes/:id/connect | 连接/恢复 sandbox |
Sandbox.create()支持的完整参数如下:
| 参数 | 类型 | 说明 |
|---|---|---|
template | str | 沙箱模板 ID(必填) |
allow_internet_access | bool | 是否允许出网,默认 True |
network | dict | 网络策略,allow_out或deny_out(CIDR 列表) |
metadata | dict | 扩展元数据,如host-mount(JSON 字符串) |
timeout | int | 沙箱最大存活秒数 |
值得补充的是,CubeAPI/src/routes.rs 表明 CubeAPI 在路由层还内置了鉴权与限流:当配置了auth_callback_url或cube_api_key时,所有 sandbox 相关路由会叠加unified_auth中间件(sandbox 路由额外叠加rate_limit限流中间件),并为每条请求生成 X-Request-ID 与 Trace 日志。若未配置任何鉴权,则这些路由直接裸奔——因此在生产部署时务必通过配置启用认证。
6. 与 OpenClaw 集成:让 Agent 自动触发沙箱执行
Skill 的定位正是为 OpenClaw 等 Agent 框架提供即插即用的代码执行能力。完整接入流程见 examples/openclaw-integration/README_zh.md:
- 部署 Cube Sandbox环境,获得可用的实例。
- 为 CubeProxy 配置 HTTPS(或直接用 HTTP 访问,注意
Host头格式)。 - 创建代码模板:
cubemastercli tpl create-from-image \ --image cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest \ --writable-layer-size 1G \ --expose-port 49999 \ --expose-port 49983 \ --probe 49999镜像仓库说明:国内优先使用
cube-sandbox-cn.tencentcloudcr.com/cube-sandbox/sandbox-code:latest;境外访问推荐使用cube-sandbox-int.tencentcloudcr.com/cube-sandbox/sandbox-code:latest。记录命令输出的template_id。
- 安装 OpenClaw Skill:将
cube-sandboxskill 目录复制到 OpenClaw workspace 并重启 Gateway:
cp -r examples/openclaw-integration/skills/cube-sandbox/ ~/.openclaw/workspace/skills/ openclaw gateway restart- 配置环境变量(Shell 或 OpenClaw 环境)。
安装完成后,skill 会被"在沙箱里跑这段代码""安全执行 Python""隔离环境运行""cube sandbox"等语句自动触发。用户可直接发出自然语言指令,例如:
- "在沙箱里跑一段 Python,计算 1 到 100 的和"
- "用沙箱执行
uname -a并返回结果" - "在完全断网的沙箱中运行这段代码"
- "读取沙箱中 /etc/hosts 的内容"
Skill 与 E2B API 的映射关系汇总:
| 能力 | E2B API |
|---|---|
| 执行 Python | sandbox.run_code(code) |
| Shell 命令 | sandbox.commands.run(cmd) |
| 读文件 | sandbox.files.read(path) |
| 写文件 | sandbox.files.write(path, content) |
| 暂停 | sandbox.pause() |
| 恢复 | sandbox.connect() |
| 断网 | Sandbox.create(allow_internet_access=False) |
| CIDR 白名单 | Sandbox.create(network={"allow_out": [...]}) |
| CIDR 黑名单 | Sandbox.create(network={"deny_out": [...]}) |
| 宿主机挂载 | Sandbox.create(metadata={"host-mount": ...}) |
7. 常见问题排查
7.1 域名解析失败
错误:[Errno 8] nodename nor servname provided, or not known
原因:SDK 无法解析沙箱返回的 domain(如49999-{sandboxID}.cube.app)。
首选方案:确认 Cube 内置 DNS 服务是否正常运行,或联系管理员检查 DNS 配置。
备用方案:手动写入 /etc/hosts
当 DNS 服务不可用时,可由 AI Agent 在创建沙箱后将所需域名临时写入/etc/hosts,沙箱销毁后再清除。其原理是:create_sandbox返回的 sandbox 信息中包含sandbox_id和domain(如cube.app);CubeProxy 的域名格式为<port>-<sandboxId>-<domain>,对应 CubeProxy 所在宿主机 IP;需要访问哪些端口(如49999、49983),就为每个端口各写一条 hosts 记录。
操作示例(假设 CubeProxy 宿主机 IP 为127.0.0.1,sandbox_id 为abc123,domain 为cube.app):
import subprocess import os PROXY_IP = "127.0.0.1" # CubeProxy 所在宿主机 IP PORTS = [49999, 49983] # 需要访问的沙箱服务端口 def add_hosts(sandbox_id: str, domain: str, ports: list[int], ip: str): """创建沙箱后写入 /etc/hosts""" entries = [] for port in ports: hostname = f"{port}-{sandbox_id}-{domain}" entries.append(f"{ip} {hostname} # cube-sandbox-{sandbox_id}") lines = "\n".join(entries) + "\n" # 需要 root 权限 subprocess.run(["sudo", "tee", "-a", "/etc/hosts"], input=lines.encode(), check=True) print(f"Added hosts entries:\n{lines}") def remove_hosts(sandbox_id: str): """沙箱销毁后清除 /etc/hosts 中对应记录""" subprocess.run( ["sudo", "sed", "-i", f"/# cube-sandbox-{sandbox_id}/d", "/etc/hosts"], check=True ) print(f"Removed hosts entries for sandbox {sandbox_id}") # 使用示例 from e2b_code_interpreter import Sandbox sb = Sandbox.create(template=os.environ['CUBE_TEMPLATE_ID']) try: add_hosts(sb.sandbox_id, "cube.app", PORTS, PROXY_IP) result = sb.run_code("print('hello')") print(result) finally: sb.kill() remove_hosts(sb.sandbox_id)⚠️ 写入
/etc/hosts需要 sudo 权限。沙箱异常退出时注意在finally块中确保清理,避免残留脏记录。
7.2 SSL 证书错误
错误:SSL 证书校验失败(如SSL: CERTIFICATE_VERIFY_FAILED)
解决方案:
- 方式一:设置
SSL_CERT_FILE环境变量(指向 CA 根证书路径,例如/root/.local/share/mkcert/rootCA.pem)。 - 方式二:在代码中禁用证书校验(仅测试环境)。
7.3 502 Bad Gateway
错误:API 返回 502
原因:Cube Sandbox 服务端不可用。
解决方案:检查服务状态和日志;联系服务管理员。
7.4 其他常见问题速查
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| Skill 未触发 | Skill 未安装 | 确认~/.openclaw/workspace/skills/cube-sandbox/存在 |
Template not found | CUBE_TEMPLATE_ID错误 | 重新运行cubemastercli tpl list |
hostPath ... is not within an allowed mount prefix | 挂载路径超出允许前缀 | 将数据移到/data/shared/下,或更新allowed_host_mount_prefixes配置 |
Read-only file system | 挂载时设置了readOnly: true | 将挂载改为readOnly: false,或改写入沙箱的可写路径 |
8. 更多资源
- API 接口与参数完整参考:examples/openclaw-integration/skills/cube-sandbox/references/api.md
- 完整可运行示例(create/exec_code/cmd/read/pause/挂载/三种网络模式):examples/openclaw-integration/skills/cube-sandbox/references/examples.md
- 宿主机挂载机制的完整文档与排障:examples/host-mount/README.md
- 网络策略三种模式与动态更新示例:examples/network-policy/README.md
- 接入 OpenClaw 的端到端指南:examples/openclaw-integration/README_zh.md
- CubeAPI 路由与超时预算实现:CubeAPI/src/routes.rs
- 沙箱生命周期 handler 实现:CubeAPI/src/handlers/sandboxes.rs
【免费下载链接】CubeSandboxInstant, Concurrent, Secure & Lightweight Sandbox for AI Agents.项目地址: https://gitcode.com/GitHub_Trending/cu/CubeSandbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考