OpenSandbox 1.1.0:阿里开源的 AI 沙箱平台,这次把版本号也管明白了

大模型写的代码,你敢直接跑在自己的服务器上吗?

随着 Claude Code、Qwen Code、Codex CLI 这些 Coding Agent 落地越来越深,这个问题变得很现实。模型输出的本质是不可信输入——命令注入、文件越权、恶意外联,哪一样出事都够喝一壶。把它直接交给宿主机执行,跟把服务器钥匙交给一个随时可能幻觉的实习生没什么区别。

OpenSandbox 就是干这个的。阿里开源(现由 opensandbox-group 维护)、Apache 2.0 协议、已被 CNCF Landscape 收录,定位是通用的 AI 应用沙箱平台:一套多语言 SDK、一套统一的沙箱 API、可插拔的运行时。Coding Agent 跑代码、GUI Agent 开浏览器、批量评测智能体、AI 代码解释器、强化学习训练,这些场景它都覆盖。

最近项目发了 1.1.0。我翻了发布说明和版本治理文档,这个版本的看点不只是功能——他们连版本号这件事都重做了一遍。下面从架构讲起,再说说 1.1.0 到底改了什么。文中的代码示例统一用 C# 写,.NET 同学可以直接抄。

架构:协议写在代码前面

OpenSandbox 分四层,从上往下是 SDK 层、协议规范层、运行时层、沙箱实例层。

OpenSandbox架构图

很多项目是先写代码、后补文档,接口藏在实现里。OpenSandbox 反着来:先用 OpenAPI 规范定义两套契约——沙箱生命周期规范(sandbox-lifecycle.yml)和沙箱执行规范(execd-api.yaml)——然后 SDK 和运行时都去对这两份规范。好处很直接:SDK 和运行时实现彻底解耦,谁都可以写个符合协议的自定义运行时接进来,不用动客户端代码。这一点,同类项目(Daytona、OpenShell)目前都还没做。

几个关键组件:

  • execd 是注入到每个沙箱容器里的执行守护进程。SDK 对沙箱的所有操作——跑命令、读写文件、执行代码——走的都是 execd 暴露的 HTTP API。沙箱创建时由运行时自动注入,用户不用管。

  • Server 是控制平面,FastAPI 写的,负责沙箱生命周期:可插拔后端(Docker / Kubernetes)、TTL 清理、API Key 认证、资源限额,服务重启后还能自动恢复过期计时器。

  • SDK 覆盖五种语言(Python、Java/Kotlin、TypeScript、C#、Go),核心组件完全一致:Sandbox 管生命周期,Commands 跑命令,Filesystem 操作文件,CodeInterpreter 是基于 Jupyter 内核协议的多语言有状态解释器。另外还有 osb 命令行工具和官方 MCP Server——后者可以让 Claude Code、Cursor 这类客户端直接通过 MCP 协议操作沙箱,一行配置,零集成代码。

贴一段 C# 的最小示例感受下(dotnet add package Alibaba.OpenSandbox):

using Alibaba.OpenSandbox;
using Alibaba.OpenSandbox.Models;

// 1. 从 alpine 镜像创建沙箱
var sandbox = await Sandbox.CreateAsync("alpine");

try
{
    // 2. 执行 shell 命令
    var execution = await sandbox.Commands.RunAsync("echo 'Hello OpenSandbox!'");
    Console.WriteLine(execution.Logs.Stdout[0].Text);

    // 3. 写入一个脚本文件
    await sandbox.Files.WriteFilesAsync(new[]
    {
        new WriteEntry
        {
            Path = "/tmp/hello.sh",
            Data = "echo \"Hello $1\"\necho '2 + 2 =' $((2 + 2))",
            Mode = 755
        }
    });

    // 4. 读回文件内容
    var content = await sandbox.Files.ReadFileAsync("/tmp/hello.sh");
    Console.WriteLine($"Content: {content}");

    // 5. 执行脚本
    var run = await sandbox.Commands.RunAsync("sh /tmp/hello.sh OpenSandbox");
    foreach (var log in run.Logs.Stdout)
        Console.WriteLine(log.Text);
}
finally
{
    // 6. 销毁沙箱
    await sandbox.DestroyAsync();
}

安全隔离:从 runc 到 Firecracker,自己挑档位

跑 AI 生成的代码,安全是底线。OpenSandbox 把隔离强度做成了多档可选:

运行时 隔离机制 启动开销 适合什么
runc(默认) 进程级 cgroup 约 0ms 受信任的负载、本地开发
gVisor 用户态内核 约 10~50ms 通用负载
Kata(QEMU) 完整虚拟机 约 500ms 隔离要求最高
Kata(Firecracker) 轻量 MicroVM 约 125ms 高密度部署
Kata(CLH) Cloud Hypervisor 约 200ms 性能和隔离折中

网络这块也做得比较细。入口有 Ingress 网关,是个 HTTP/WebSocket 反向代理,支持按请求头(OpenSandbox-Ingress-To: <sandbox-id>-<port>)或 URI 路径两种路由方式,还有个贴心的设计:沙箱被访问时自动续期,实现「按需保活」。出口有 Egress Sidecar,跟沙箱容器共享网络命名空间,用 DNS 代理加 nftables 做双层拦截,FQDN 级别的白名单,默认拒绝所有出站流量——沙箱里的代码想偷偷外联,门都没有。

还有一个设计原则要单独说:沙箱是独占的,一人一个,不支持共用。理由很实在——沙箱里只有一个 execd 入口,文件系统命名空间唯一,进程互相可见,TTL 到期是整个沙箱一起死的,多人共用必然互相踩。所以正确姿势是每个会话独占一个沙箱,平台负责批量创建和回收。这正是 Kubernetes 运行时(BatchSandbox / agent-sandbox)擅长的事:给海量并发用户快速分沙箱,隔离和弹性两不误。

1.1.0:为什么不是 1.0.0

先说个有意思的细节。这次发的是 1.1.0,但 1.0.0 是故意跳过的。

原因有点无奈:Maven Central 上 com.alibaba.opensandbox:sandbox 已经发到 1.0.19 了,Go module proxy 也到了 v1.0.5,而这些包仓库是不可变的——发出去的版本收不回。统一伞版本必须从一个高于所有已消耗版本的新「线」开始。1.0.20 倒是能避开冲突,但按他们的规则,Z > 0 是留给线内快照的,不算合法的线起点。算来算去,只能是 1.1.0。

这个「伞版本」(umbrella release)就是 1.1.0 最大的治理动作:Server、组件镜像、K8s controller、Helm chart、CLI、全部 SDK,所有产物共用同一个版本号,从同一个 commit 切出来,再由 Sigstore 签名的 BOM 固定。发版节奏也定了:每两周开一条新线(X.Y.0),只维护最新线,没有 LTS,紧急 CVE 可以破例回补一次上一个线。Helm chart 不单独发布,直接在 release tag 上自己 render:

git checkout release-1.1.0
helm template ./manifests/charts/opensandbox | kubectl apply -f -

功能层面的三个重头戏

Firecracker 微虚拟机(Fast Sandbox)首次亮相。 这是 1.1.0 最重磅的东西:一个基于 Firecracker microVM 的模板化沙箱平台,通过 FastPath v2 gRPC 控制面接入,Server、Ingress、execd 和全部五种 SDK 都已集成。它带来的玩法是混合部署——长生命周期的 K8s 容器负载和短生命周期的 microVM 沙箱跑在同一个集群里。预热的 Firecracker 沙箱池能做到约 80ms 启动;暂停时把状态 checkpoint 到 artifact store、算力全释放,恢复时在任意宿主机上原地复活。

快照持久化升级。 新增可选的 PostgreSQL 快照存储(连接池、CAS 语义、多进程 HA),附赠 migrate-snapshots 命令把 SQLite 里的旧记录搬过去;快照状态收敛也从阻塞轮询改成了 per-namespace watch。

沙箱生命周期 Hook(OSEP-0020)。 创建沙箱时可以声明 preStart 和 periodic hook。execd 侧的实现挺讲究:preStart 会挡住用户入口点直到 hook 完成,periodic hook 走 init-reaper 感知的进程路径,配了 fail-closed 的 TERM/KILL 看门狗。

其他值得一看的改动

发布说明很长,我挑了些干货:

  • Server 新增稳定的诊断 API(按 logs / events 范围取日志和事件);HTTP 请求指标经 OTLP 导出;沙箱池满了会返回 429 + Retry-After,而不是让你干等超时
  • execd 的 /command 支持原生 argv 执行,绕过 shell 解析,五种 SDK 已全部打通;新增 POST /init 运行时初始化握手,把沙箱身份从镜像构建期挪到运行时绑定
  • Ingress 的路由签名改成了常量时间比对(防时序侧信道);WebSocket 代理从停止维护的 gorilla/websocket 迁到了 coder/websocket
  • Egress 上了实验性的 Fleet Profile(多沙箱出口控制面 + 按租户的凭据保险库)和凭据绑定的 TLS 拦截管线——后者这版只是打地基,默认不开
  • 所有发布镜像用 Cosign 无密钥签名并附 provenance 证明,生产环境建议按摘要钉版本

升级注意几个坑:agent-sandbox provider 迁移到了 agents.x-k8s.io/v1beta1,升级前得先装 beta CRDs;charts 目录挪到了 manifests/charts/;informer_enabled 配置项删了;CodeInterpreter 创建默认改成严格就绪检查,依赖旧行为的要显式设置;生命周期 hook 这版在 Docker 运行时上会被拒。

上手:五分钟跑起来

# 1. 装服务端并初始化(Docker 运行时)
uvx opensandbox-server init-config ~/.sandbox.toml --example docker
uvx opensandbox-server

# 健康检查
curl http://127.0.0.1:8080/health   # {"status": "healthy"}

# 2. 装 C# SDK
dotnet add package Alibaba.OpenSandbox --version 1.1.0

# 3. 或者用 CLI
pip install opensandbox-cli
osb config init && osb config set connection.domain localhost:8080
osb sandbox create --image python:3.12 --timeout 30m -o json
osb command run <sandbox-id> -o raw -- python -c "print(1 + 1)"

创建带出口策略的沙箱也很直白,比如只允许访问 pypi.org:

// 默认拒绝所有出站,只放行 pypi.org
var sandbox = await Sandbox.CreateAsync(new SandboxCreateOptions
{
    Image = "python:3.12",
    NetworkPolicy = new NetworkPolicy
    {
        DefaultAction = "deny",
        Egress = new[]
        {
            new NetworkRule { Action = "allow", Target = "*.pypi.org" },
            new NetworkRule { Action = "allow", Target = "pypi.org" }
        }
    }
});

// 沙箱里 pip install 只能连 pypi.org,其他外联全部被拒
var result = await sandbox.Commands.RunAsync("pip install requests");
Console.WriteLine(result.Text());

和 Daytona、OpenShell 怎么选

顺手对比一下同类项目:

OpenSandbox Daytona OpenShell(NVIDIA)
定位 协议标准化的 AI 沙箱平台 AI 代码执行基础设施 Agent 安全隐私运行时
隔离方案 runc/gVisor/Kata/Firecracker 全谱系 Docker 容器 + iptables Landlock + Seccomp + OPA 四层纵深
多语言 SDK 5 种 5 种 主要 Python
大规模调度 K8s 原生 多 Runner 扩展 Alpha,单机为主
特色 OpenAPI 协议标准、MCP 原生、CNCF Landscape 90ms 内冷启动、快照、Dashboard 推理隐私路由、凭据不落盘
成熟度 生产可用 生产可用,有托管云 Alpha

我的看法:要多框架接入、要 K8s 大规模批量调度,选 OpenSandbox;要完整的组织级 Coding Agent 平台(快照、Dashboard、多区域),看 Daytona;个人跑 Agent、特别在意凭据安全和推理隐私,可以试 OpenShell——但要接受它还是 Alpha。

写在最后

OpenSandbox 1.1.0 的分量,一半在功能,一半在治理。伞版本加签名 BOM,把「一套版本号管所有产物」这件事落到了实处;Firecracker 集成补上了微虚拟机这块拼图;OSEP 提案机制则说明项目在往规范化社区治理走。

「一人一个沙箱,用完即焚」——听起来朴素,但对要把 AI Agent 真正跑上生产的团队来说,这可能就是最正确的答案。


posted @ 2026-09-27 19:47  张善友  阅读(81)  评论(0)    收藏  举报