沙盒(三):Firecracker、Jupyter Kernel、E2B、AIO、k8s-sigs、Agent-Sandbox

沙盒系列文章:

进入AI、LLM时代,沙盒技术也迎来不少变革。AI时代的沙盒不是传统意义上"限制型"的沙箱,而是一个全新的基础设施层:它既要提供极致的隔离安全,又要支持毫秒级的启动速度;既要兼容多语言运行时,又要暴露简洁的REST/gRPC API供AI Agent调用;既要能在云端弹性扩缩,又要能自托管到私有网络。

Firecracker

官网,AWS开源(GitHub,35.2K Star,2.5K Fork)轻量级虚拟化运行环境,基于Rust语言编写、极简VMM(Virtual Machine Monitor),可在AWS云上和本地环境中使用。Firecracker MicroVM同时具备传统虚拟机的安全性和工作负载隔离能力以及容器的速度和资源利用率。

与QEMU、KVM这种庞然大物不同,Firecracker只做一件事:快速启动轻量级microVM。去掉传统虚拟机模拟器中的一切非必要组件(ACPI、BIOS、PCI设备模拟等),只保留最核心的设备模型:virtio-netvirtio-blkserial console

工作示意图

关键特性:

特性 数值 说明
最小内存 5MB 比同类方案低1-2个数量级
启动时间 125ms 从创建到SSH就绪
微VM开销 <1% 相较于裸金属(bare-metal)的性能损失
安全边界 jailer 独立chroot+cgroup+seccomp

传统虚拟机启动慢,主要是因为BIOS/UEFI初始化、内核解压、设备枚举、systemd初始化等耗时。Firecracker优化三方面:

  1. 精简内核:使用定制的小型Linux内核,去掉大量不需要的驱动和模块
  2. 无bootloader:Firecracker直接将内核加载到内存,跳过GRUB等引导加载器
  3. 最小化设备模型:只模拟virtio-netvirtio-blk,减少设备枚举时间

每个microVM启动时都会通过jailer进程设置:

  • chroot:每个VM被限制在自己的文件系统根中
  • cgroup:CPU/内存/网络带宽都有严格上限
  • seccomp-bpf:限制系统调用白名单

配置示例:

json 复制代码
{
  "vcpu_count": 2,
  "mem_size_mib": 256,
  "ht_enabled": false,
  "boot_args": "console=ttyS0 reboot=k panic=1 pci=off",
  "drives": [
    {
      "drive_id": "rootfs",
      "path_on_host": "/srv/jailer/firecracker/rootfs.ext4",
      "is_root_device": true,
      "is_read_only": false
    }
  ],
  "network_interfaces": [
    {
      "iface_id": "eth0",
      "host_dev_name": "tap0"
    }
  ]
}

运行在为Firecracker优化过的Amazon裸金属EC2服务器上的MicroVM是多租户容器服务的理想选择,可为最新的微服务或无服务器架构的现代应用提供方便、敏捷的开发和部署环境。

推荐阅读:深度解析AWS Firecracker原理篇--虚拟化与容器运行时技术

Jupyter Kernel

即Jupyter内核,提供编程语言支持的核心组件,就是编译器。Jupyter默认使用IPython作为其内核,支持Python,IPython内核提供强大Python交互式计算环境。此外,Jupyter还支持其他内核,如R、Julia等,意味着,在Jupyter中可使用许多其他语言。

虚拟环境是Python环境的副本,独立于系统全局Python环境。通过虚拟环境,可在不同项目中使用不同的库和库版本,避免冲突。在Jupyter中,可将虚拟环境添加为Kernel,从而使用该虚拟环境来运行代码:

bash 复制代码
# 激活虚拟环境
conda activate myenv
# 安装ipykernel
conda install ipykernel
# 将虚拟环境添加为Kernel
python -m ipykernel install --user --name myenv --display-name "My Environment"

E2B

官网,End-to-End Bytes缩写,AI Agent领域最知名的云沙盒平台之一,使用Python语言,基于Firecracker,为Agent提供安全沙盒化执行环境,让LLM生成的代码在一个完全隔离的微型虚拟机中运行。

使用HashiCorp Nomad作为调度器,Consul作为服务发现,组合优势:

  • 轻量级调度:Nomad比k8s更轻,单二进制部署
  • 批量作业优化:沙盒本质上是短生命周期批量作业
  • 资源打包:Nomad可更高效地将microVM packing到物理机

并没有为每种语言实现独立引擎,而是利用Jupyter内核作为统一的语言执行通道:
#mermaid-svg-jnSv4OpAEwrGg0vw{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-jnSv4OpAEwrGg0vw .error-icon{fill:#552222;}#mermaid-svg-jnSv4OpAEwrGg0vw .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jnSv4OpAEwrGg0vw .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jnSv4OpAEwrGg0vw .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jnSv4OpAEwrGg0vw .marker.cross{stroke:#333333;}#mermaid-svg-jnSv4OpAEwrGg0vw svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jnSv4OpAEwrGg0vw p{margin:0;}#mermaid-svg-jnSv4OpAEwrGg0vw .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw .cluster-label text{fill:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw .cluster-label span{color:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw .cluster-label span p{background-color:transparent;}#mermaid-svg-jnSv4OpAEwrGg0vw .label text,#mermaid-svg-jnSv4OpAEwrGg0vw span{fill:#333;color:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw .node rect,#mermaid-svg-jnSv4OpAEwrGg0vw .node circle,#mermaid-svg-jnSv4OpAEwrGg0vw .node ellipse,#mermaid-svg-jnSv4OpAEwrGg0vw .node polygon,#mermaid-svg-jnSv4OpAEwrGg0vw .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-jnSv4OpAEwrGg0vw .rough-node .label text,#mermaid-svg-jnSv4OpAEwrGg0vw .node .label text,#mermaid-svg-jnSv4OpAEwrGg0vw .image-shape .label,#mermaid-svg-jnSv4OpAEwrGg0vw .icon-shape .label{text-anchor:middle;}#mermaid-svg-jnSv4OpAEwrGg0vw .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-jnSv4OpAEwrGg0vw .rough-node .label,#mermaid-svg-jnSv4OpAEwrGg0vw .node .label,#mermaid-svg-jnSv4OpAEwrGg0vw .image-shape .label,#mermaid-svg-jnSv4OpAEwrGg0vw .icon-shape .label{text-align:center;}#mermaid-svg-jnSv4OpAEwrGg0vw .node.clickable{cursor:pointer;}#mermaid-svg-jnSv4OpAEwrGg0vw .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-jnSv4OpAEwrGg0vw .arrowheadPath{fill:#333333;}#mermaid-svg-jnSv4OpAEwrGg0vw .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-jnSv4OpAEwrGg0vw .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-jnSv4OpAEwrGg0vw .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jnSv4OpAEwrGg0vw .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-jnSv4OpAEwrGg0vw .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jnSv4OpAEwrGg0vw .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-jnSv4OpAEwrGg0vw .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-jnSv4OpAEwrGg0vw .cluster text{fill:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw .cluster span{color:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-jnSv4OpAEwrGg0vw .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-jnSv4OpAEwrGg0vw rect.text{fill:none;stroke-width:0;}#mermaid-svg-jnSv4OpAEwrGg0vw .icon-shape,#mermaid-svg-jnSv4OpAEwrGg0vw .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-jnSv4OpAEwrGg0vw .icon-shape p,#mermaid-svg-jnSv4OpAEwrGg0vw .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-jnSv4OpAEwrGg0vw .icon-shape .label rect,#mermaid-svg-jnSv4OpAEwrGg0vw .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-jnSv4OpAEwrGg0vw .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-jnSv4OpAEwrGg0vw .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-jnSv4OpAEwrGg0vw :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-jnSv4OpAEwrGg0vw .container>*{fill:#f8f9fa!important;stroke:#adb5bd!important;stroke-width:2px!important;}#mermaid-svg-jnSv4OpAEwrGg0vw .container span{fill:#f8f9fa!important;stroke:#adb5bd!important;stroke-width:2px!important;}#mermaid-svg-jnSv4OpAEwrGg0vw .module>*{fill:#e3f2fd!important;stroke:#0d6efd!important;stroke-width:1px!important;}#mermaid-svg-jnSv4OpAEwrGg0vw .module span{fill:#e3f2fd!important;stroke:#0d6efd!important;stroke-width:1px!important;}#mermaid-svg-jnSv4OpAEwrGg0vw .kernel>*{fill:#d1e7dd!important;stroke:#198754!important;stroke-width:1px!important;}#mermaid-svg-jnSv4OpAEwrGg0vw .kernel span{fill:#d1e7dd!important;stroke:#198754!important;stroke-width:1px!important;} E2B Sandbox (microVM)
Jupyter Gateway
WebSocket (Jupyter Kernel Protocol)
IPython
IJava
gophernotes
ITypeScript
gRPC 协议适配层

(统一语言接口,屏蔽内核差异)

Jupyter内核已经是一个非常成熟的REPL协议,天然支持代码执行、状态保持、变量查看、中断等功能。E2B只需在Jupyter之上封装一层gRPC接口,即可快速支持多种语言。

除提供SaaS平台,采用按需计费模式:

  • Sandbox Session:按沙盒存在时间收费(美元/分钟)
  • 存储:snapshot持久化额外收费
  • Team Plan:提供自定义镜像和团队管理功能

此外,在GitHub开源社区维护一系列项目:

优点:

  • Firecracker microVM提供硬件级隔离,安全性一流
  • 125ms启动,接近容器的启动速度
  • 多语言支持成熟(Python/JS/Java/Go/Ruby)
  • SDK设计简洁,AI Agent集成方便
  • Jupyter内核协议成熟稳定

缺点:

  • Firecracker内核虚拟化在各云环境的兼容性不同
  • 长任务场景下成本较高(按分钟计费)
  • IPython内核在大型输出时内存占用高

实战

E2B提供Python和JavaScript两大SDK。

通过pip安装:pip install e2b

Python SDK示例:

py 复制代码
from e2b import Sandbox

# 创建Python沙盒
sandbox = Sandbox(template="base")
# 执行代码
code = """
	import math
	result = math.factorial(100)
	print(f"100! = {result}")
"""
execution = sandbox.run_code(code)
print(execution.logs.stdout)
# 创建文件
sandbox.files.write("/tmp/data.txt", "hello e2b")
# 读取文件
content = sandbox.files.read("/tmp/data.txt")
# 安装包
sandbox.commands.run("pip install requests")
# 清理
sandbox.close()

通过npm安装:npm install e2b

JavaScript SDK示例:

js 复制代码
import { Sandbox } from 'e2b';

const sandbox = await Sandbox.create({ template: 'base' });
const { stdout } = await sandbox.runCode('print("Hello from E2B!")');
console.log(stdout);
await sandbox.kill();

OpenSandbox

另起一篇,参考阿里开源沙盒项目OpenSandbox

AIO

论文官网,AIO Sandbox,Python语言编写、开源(GitHub,5.3K Star,475 Fork) 一体化(all-in-one)的代理沙箱环境,将浏览器、Shell、文件、MCP操作和VSCode服务器集成在Docker容器中。基于云原生轻量级沙箱技术构建,为AI代理和开发人员提供统一安全的执行环境。

架构图
#mermaid-svg-SM5tarwuzkNzYaCJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SM5tarwuzkNzYaCJ .error-icon{fill:#552222;}#mermaid-svg-SM5tarwuzkNzYaCJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SM5tarwuzkNzYaCJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SM5tarwuzkNzYaCJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SM5tarwuzkNzYaCJ .marker.cross{stroke:#333333;}#mermaid-svg-SM5tarwuzkNzYaCJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SM5tarwuzkNzYaCJ p{margin:0;}#mermaid-svg-SM5tarwuzkNzYaCJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ .cluster-label text{fill:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ .cluster-label span{color:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ .cluster-label span p{background-color:transparent;}#mermaid-svg-SM5tarwuzkNzYaCJ .label text,#mermaid-svg-SM5tarwuzkNzYaCJ span{fill:#333;color:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ .node rect,#mermaid-svg-SM5tarwuzkNzYaCJ .node circle,#mermaid-svg-SM5tarwuzkNzYaCJ .node ellipse,#mermaid-svg-SM5tarwuzkNzYaCJ .node polygon,#mermaid-svg-SM5tarwuzkNzYaCJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SM5tarwuzkNzYaCJ .rough-node .label text,#mermaid-svg-SM5tarwuzkNzYaCJ .node .label text,#mermaid-svg-SM5tarwuzkNzYaCJ .image-shape .label,#mermaid-svg-SM5tarwuzkNzYaCJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-SM5tarwuzkNzYaCJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SM5tarwuzkNzYaCJ .rough-node .label,#mermaid-svg-SM5tarwuzkNzYaCJ .node .label,#mermaid-svg-SM5tarwuzkNzYaCJ .image-shape .label,#mermaid-svg-SM5tarwuzkNzYaCJ .icon-shape .label{text-align:center;}#mermaid-svg-SM5tarwuzkNzYaCJ .node.clickable{cursor:pointer;}#mermaid-svg-SM5tarwuzkNzYaCJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SM5tarwuzkNzYaCJ .arrowheadPath{fill:#333333;}#mermaid-svg-SM5tarwuzkNzYaCJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SM5tarwuzkNzYaCJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SM5tarwuzkNzYaCJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SM5tarwuzkNzYaCJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SM5tarwuzkNzYaCJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SM5tarwuzkNzYaCJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SM5tarwuzkNzYaCJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SM5tarwuzkNzYaCJ .cluster text{fill:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ .cluster span{color:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SM5tarwuzkNzYaCJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SM5tarwuzkNzYaCJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-SM5tarwuzkNzYaCJ .icon-shape,#mermaid-svg-SM5tarwuzkNzYaCJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SM5tarwuzkNzYaCJ .icon-shape p,#mermaid-svg-SM5tarwuzkNzYaCJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SM5tarwuzkNzYaCJ .icon-shape .label rect,#mermaid-svg-SM5tarwuzkNzYaCJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SM5tarwuzkNzYaCJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SM5tarwuzkNzYaCJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SM5tarwuzkNzYaCJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-SM5tarwuzkNzYaCJ .layerBox>*{fill:#f8f9fa!important;stroke:#adb5bd!important;stroke-width:2px!important;stroke-dasharray:4 4!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .layerBox span{fill:#f8f9fa!important;stroke:#adb5bd!important;stroke-width:2px!important;stroke-dasharray:4 4!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .apiNode>*{fill:#e3f2fd!important;stroke:#1976d2!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .apiNode span{fill:#e3f2fd!important;stroke:#1976d2!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .orchestNode>*{fill:#fff3e0!important;stroke:#f57c00!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .orchestNode span{fill:#fff3e0!important;stroke:#f57c00!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .k8sNode>*{fill:#e8f5e9!important;stroke:#388e3c!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .k8sNode span{fill:#e8f5e9!important;stroke:#388e3c!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .routeNode>*{fill:#f3e5f5!important;stroke:#7b1fa2!important;stroke-width:1px!important;}#mermaid-svg-SM5tarwuzkNzYaCJ .routeNode span{fill:#f3e5f5!important;stroke:#7b1fa2!important;stroke-width:1px!important;} 路由模式
路径路由: /e2b/v1/sandboxes/{id}
子域名路由: {id}.sandbox.example.com
Kubernetes集群
Sandbox1

(E2B 兼容)
Sandbox2

(E2B 兼容)
SandboxN

(E2B 兼容)
沙盒编排器
实例管理
模板管理
资源调度
API网关(E2B协议兼容)
POST /e2b/v1/sandboxes

→ 创建沙盒
GET /e2b/v1/sandboxes/{id}

→ 查询沙盒
POST /e2b/v1/sandboxes/{id}/close

→ 关闭
POST /e2b/v1/sandboxes/{id}/refreshes

→ 续期

支持两种路由模式:

  • 路径路由模式:Path-based Routing,https://sandbox.example.com/e2b/v1/sandboxes/{sandbox_id}
  • 子域名路由模式:Subdomain-based Routing,https://{sandbox_id}.sandbox.example.com

子域名路由的优势:

  • 每个沙盒有独立的子域名,便于网络策略隔离
  • 减少路径解析开销
  • 更符合RESTful设计规范

核心API:

  • /v1/sandbox:获取沙盒环境信息
  • /v1/shell/exec:执行shell命令
  • /v1/file/read:读取文件内容
  • /v1/file/write:写入文件内容
  • /v1/browser/screenshot:浏览器截图
  • /v1/jupyter/execute:执行Jupyter代码

暴露的MCP服务器及其工具能力

服务 可用工具
browser navigate,screenshot,click,type,scroll
file read,write,list,search,replace
shell exec,create_session,kill
markitdown convert,extract_text,extract_images

实战

基于Docker Compose部署:

bash 复制代码
version: '3.8'
services:
  sandbox:
    container_name: aio-sandbox
    image: ghcr.io/agent-infra/sandbox:latest
    volumes:
      - /tmp/gem/vite-project:/home/gem/vite-project
    security_opt:
      - seccomp:unconfined
    extra_hosts:
      - "host.docker.internal:host-gateway"
    restart: "unless-stopped"
    shm_size: "2gb"
    ports:
      - "127.0.0.1:${HOST_PORT:-8080}:8080"
    environment:
      PROXY_SERVER: ${PROXY_SERVER:-host.docker.internal:7890}
      JWT_PUBLIC_KEY: ${JWT_PUBLIC_KEY:-}
      DNS_OVER_HTTPS_TEMPLATES: ${DNS_OVER_HTTPS_TEMPLATES:-}
      WORKSPACE: ${WORKSPACE:-"/home/gem"}
      HOMEPAGE: ${HOMEPAGE:-}
      BROWSER_EXTRA_ARGS: ${BROWSER_EXTRA_ARGS:-}
      TZ: ${TZ:-Asia/Singapore}
      WAIT_PORTS: ${WAIT_PORTS:-}

执行命令docker compose up -d,没问题的话,将得到沙盒服务器:http://localhost:8080

当然也支持通过k8s Yaml文件部署:

yml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: aio-sandbox
spec:
  replicas: 2
  selector:
    matchLabels:
      app: aio-sandbox
  template:
    metadata:
      labels:
        app: aio-sandbox
    spec:
      containers:
      - name: aio-sandbox
        image: ghcr.io/agent-infra/sandbox:latest
        ports:
        - containerPort: 8080
        resources:
          limits:
            memory: "2Gi"
            cpu: "1000m"

官方提供Python、TypeScript/JavaScript、Go等语言SDK。

通过pip安装:pip install agent-sandbox

Python示例:

py 复制代码
from agent_sandbox import Sandbox

# 初始化客户端
client = Sandbox(base_url="http://localhost:8080")
home_dir = client.sandbox.get_context().home_dir
# 执行shell命令
result = client.shell.exec_command(command="ls -la")
print(result.data.output)
# 文件操作
content = client.file.read_file(file=f"{home_dir}/.bashrc")
# 浏览器自动化
screenshot = client.browser.screenshot()

通过npm安装:npm install @agent-infra/sandbox

TypeScript示例:

ts 复制代码
import { Sandbox } from '@agent-infra/sandbox';

const sandbox = new Sandbox({ baseURL: 'http://localhost:8080' });
const result = await sandbox.shell.exec({ command: 'ls -la' });
console.log(result.output);
const content = await sandbox.file.read({ path: '/home/gem/.bashrc' });
const screenshot = await sandbox.browser.screenshot();

安装Go SDK:go get github.com/agent-infra/sandbox-sdk-go

Go示例省略。

将网页转换为Markdown格式,并嵌入屏幕截图:

py 复制代码
import asyncio
import base64
from playwright.async_api import async_playwright
from agent_sandbox import Sandbox

async def site_to_markdown():
    c = Sandbox(base_url="http://localhost:8080")
    home_dir = c.sandbox.get_context().home_dir
    # 浏览器自动下载HTML
    async with async_playwright() as p:
        browser_info = c.browser.get_info().data
        page = await (await p.chromium.connect_over_cdp(browser_info.cdp_url)).new_page()
        await page.goto("https://example.com", wait_until="networkidle")
        html = await page.content()
        screenshot_b64 = base64.b64encode(await page.screenshot()).decode('utf-8')

    # Jupyter,在沙盒内将HTML转换为markdown
	c.jupyter.execute_code(code=f"""
		from markdownify import markdownify
		html = '''{html}'''
		screenshot_b64 = "{screenshot_b64}"
		
		md = f"{{markdownify(html)}}\\n\\n![Screenshot](data:image/png;base64,{{screenshot_b64}})"
		with open('{home_dir}/site.md', 'w') as f:
		    f.write(md)
		print("Done!")
	""")

    list_result = c.shell.exec_command(command=f"ls -lh {home_dir}")
    print(f"Files in sandbox: {list_result.data.output}")

    return c.file.read_file(file=f"{home_dir}/site.md").data.content

if __name__ == "__main__":
    result = asyncio.run(site_to_markdown())
    print(f"Markdown saved successfully!")

官方GitHub还有更多示例代码,如集成Browser Use、LangChain、OpenAI助手等。

k8s-sigs

项目主页,使用Go+Python语言开发的开源(GitHub,3K Star,370 Fork)项目,旨在开发k8s的沙箱CRD和控制器。

架构示意图
#mermaid-svg-QbWLnLOOp50cOM69{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-QbWLnLOOp50cOM69 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-QbWLnLOOp50cOM69 .error-icon{fill:#552222;}#mermaid-svg-QbWLnLOOp50cOM69 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-QbWLnLOOp50cOM69 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-QbWLnLOOp50cOM69 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-QbWLnLOOp50cOM69 .marker.cross{stroke:#333333;}#mermaid-svg-QbWLnLOOp50cOM69 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-QbWLnLOOp50cOM69 p{margin:0;}#mermaid-svg-QbWLnLOOp50cOM69 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-QbWLnLOOp50cOM69 .cluster-label text{fill:#333;}#mermaid-svg-QbWLnLOOp50cOM69 .cluster-label span{color:#333;}#mermaid-svg-QbWLnLOOp50cOM69 .cluster-label span p{background-color:transparent;}#mermaid-svg-QbWLnLOOp50cOM69 .label text,#mermaid-svg-QbWLnLOOp50cOM69 span{fill:#333;color:#333;}#mermaid-svg-QbWLnLOOp50cOM69 .node rect,#mermaid-svg-QbWLnLOOp50cOM69 .node circle,#mermaid-svg-QbWLnLOOp50cOM69 .node ellipse,#mermaid-svg-QbWLnLOOp50cOM69 .node polygon,#mermaid-svg-QbWLnLOOp50cOM69 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-QbWLnLOOp50cOM69 .rough-node .label text,#mermaid-svg-QbWLnLOOp50cOM69 .node .label text,#mermaid-svg-QbWLnLOOp50cOM69 .image-shape .label,#mermaid-svg-QbWLnLOOp50cOM69 .icon-shape .label{text-anchor:middle;}#mermaid-svg-QbWLnLOOp50cOM69 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-QbWLnLOOp50cOM69 .rough-node .label,#mermaid-svg-QbWLnLOOp50cOM69 .node .label,#mermaid-svg-QbWLnLOOp50cOM69 .image-shape .label,#mermaid-svg-QbWLnLOOp50cOM69 .icon-shape .label{text-align:center;}#mermaid-svg-QbWLnLOOp50cOM69 .node.clickable{cursor:pointer;}#mermaid-svg-QbWLnLOOp50cOM69 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-QbWLnLOOp50cOM69 .arrowheadPath{fill:#333333;}#mermaid-svg-QbWLnLOOp50cOM69 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-QbWLnLOOp50cOM69 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-QbWLnLOOp50cOM69 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QbWLnLOOp50cOM69 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-QbWLnLOOp50cOM69 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QbWLnLOOp50cOM69 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-QbWLnLOOp50cOM69 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-QbWLnLOOp50cOM69 .cluster text{fill:#333;}#mermaid-svg-QbWLnLOOp50cOM69 .cluster span{color:#333;}#mermaid-svg-QbWLnLOOp50cOM69 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-QbWLnLOOp50cOM69 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-QbWLnLOOp50cOM69 rect.text{fill:none;stroke-width:0;}#mermaid-svg-QbWLnLOOp50cOM69 .icon-shape,#mermaid-svg-QbWLnLOOp50cOM69 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-QbWLnLOOp50cOM69 .icon-shape p,#mermaid-svg-QbWLnLOOp50cOM69 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-QbWLnLOOp50cOM69 .icon-shape .label rect,#mermaid-svg-QbWLnLOOp50cOM69 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-QbWLnLOOp50cOM69 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-QbWLnLOOp50cOM69 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-QbWLnLOOp50cOM69 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Extensions
creates
creates
references
adopts
adopts sandboxes from
creates Pod
pre-warms sandboxes
User
SandboxClaim
SandboxTemplate
Sandbox
Pod
Sandbox Runtime
SandboxWarmPool

Agent-Sandbox

项目主页,使用Go语言开发,完全兼容E2B协议的开源(GitHub,158 Star,15 Fork)项目,目标是提供可自托管的E2B替代方案,所有基于E2B SDK开发的应用,只需切换endpoint即可迁移到Agent-Sandbox。

架构图
#mermaid-svg-o1oPKRWJlqBK7YDU{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-o1oPKRWJlqBK7YDU .error-icon{fill:#552222;}#mermaid-svg-o1oPKRWJlqBK7YDU .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-o1oPKRWJlqBK7YDU .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-o1oPKRWJlqBK7YDU .marker{fill:#333333;stroke:#333333;}#mermaid-svg-o1oPKRWJlqBK7YDU .marker.cross{stroke:#333333;}#mermaid-svg-o1oPKRWJlqBK7YDU svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-o1oPKRWJlqBK7YDU p{margin:0;}#mermaid-svg-o1oPKRWJlqBK7YDU .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU .cluster-label text{fill:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU .cluster-label span{color:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU .cluster-label span p{background-color:transparent;}#mermaid-svg-o1oPKRWJlqBK7YDU .label text,#mermaid-svg-o1oPKRWJlqBK7YDU span{fill:#333;color:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU .node rect,#mermaid-svg-o1oPKRWJlqBK7YDU .node circle,#mermaid-svg-o1oPKRWJlqBK7YDU .node ellipse,#mermaid-svg-o1oPKRWJlqBK7YDU .node polygon,#mermaid-svg-o1oPKRWJlqBK7YDU .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-o1oPKRWJlqBK7YDU .rough-node .label text,#mermaid-svg-o1oPKRWJlqBK7YDU .node .label text,#mermaid-svg-o1oPKRWJlqBK7YDU .image-shape .label,#mermaid-svg-o1oPKRWJlqBK7YDU .icon-shape .label{text-anchor:middle;}#mermaid-svg-o1oPKRWJlqBK7YDU .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-o1oPKRWJlqBK7YDU .rough-node .label,#mermaid-svg-o1oPKRWJlqBK7YDU .node .label,#mermaid-svg-o1oPKRWJlqBK7YDU .image-shape .label,#mermaid-svg-o1oPKRWJlqBK7YDU .icon-shape .label{text-align:center;}#mermaid-svg-o1oPKRWJlqBK7YDU .node.clickable{cursor:pointer;}#mermaid-svg-o1oPKRWJlqBK7YDU .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-o1oPKRWJlqBK7YDU .arrowheadPath{fill:#333333;}#mermaid-svg-o1oPKRWJlqBK7YDU .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-o1oPKRWJlqBK7YDU .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-o1oPKRWJlqBK7YDU .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o1oPKRWJlqBK7YDU .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-o1oPKRWJlqBK7YDU .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o1oPKRWJlqBK7YDU .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-o1oPKRWJlqBK7YDU .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-o1oPKRWJlqBK7YDU .cluster text{fill:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU .cluster span{color:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-o1oPKRWJlqBK7YDU .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-o1oPKRWJlqBK7YDU rect.text{fill:none;stroke-width:0;}#mermaid-svg-o1oPKRWJlqBK7YDU .icon-shape,#mermaid-svg-o1oPKRWJlqBK7YDU .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-o1oPKRWJlqBK7YDU .icon-shape p,#mermaid-svg-o1oPKRWJlqBK7YDU .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-o1oPKRWJlqBK7YDU .icon-shape .label rect,#mermaid-svg-o1oPKRWJlqBK7YDU .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-o1oPKRWJlqBK7YDU .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-o1oPKRWJlqBK7YDU .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-o1oPKRWJlqBK7YDU :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-svg-o1oPKRWJlqBK7YDU .agent>*{fill:#f9f!important;stroke:#333!important;stroke-width:3px!important;}#mermaid-svg-o1oPKRWJlqBK7YDU .agent span{fill:#f9f!important;stroke:#333!important;stroke-width:3px!important;} Execute Code
Browse Web
Terminal Access
...
File R/W
State Persistence
Shared Storage
Agent A
Agent-Sandbox

Auto CRUD Sandboxes
Agent B
Agent C
Agent ...
Code Sandbox
Browser Sandbox
Computer Sandbox
Customized Sandbox
Unified Storage

NAS/OSS/S3
Kubernetes Cluster

实战

基于install.yaml文件在k8s集群里安装Agent-Sandbox,需要k8s版本大于等于1.26install.yaml文件示例

yml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: agent-sandbox
  namespace: agent-sandbox
spec:
  ingressClassName: ingress-nginx
  rules:
  - host: agent-sandbox.your-host.com
    http:
      paths:
      - backend:
          service:
            name: agent-sandbox
            port:
              number: 80
        path: /

执行命令:

bash 复制代码
kubectl create namespace agent-sandbox
kubectl apply -n agent-sandbox -f install.yaml

没出错的话,可访问http://agent-sandbox.your-host.com提供的API服务,以及http://agent-sandbox.your-host.com/mcp提供的MCP能力。

支持使用AIO提供的Python SDK连接到API Server。