OpenSandbox Code Interpreter 实战:在安全沙箱中执行多语言代码与 Kubernetes Pool 预热模式
【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox
本文基于 OpenSandbox 官方示例文档,完整讲解 Code Interpreter 沙箱的落地全流程:拉取预构建镜像、启动本地或 Kubernetes 版 OpenSandbox 服务端、使用 Python SDK 在沙箱内执行 Python/Java/Go/TypeScript 代码并捕获 stdout 与执行结果,以及通过 Pool 资源池实现免冷启动的按需分配。读完本文,你可以复制仓库中的 main.py 与 main_use_pool.py 直接在本地或 k8s 集群上跑通多语言代码解释器,并理解服务端 entrypoint 注入与 task-executor 的底层工作机制。
整体架构:Sandbox + CodeInterpreter 的分层设计
Code Interpreter 并非独立的运行时,而是构建在 OpenSandbox 通用沙箱能力之上的 SDK 层。从源码结构看,分层关系非常清晰:
- Sandbox 层(opensandbox SDK):负责沙箱基础设施——容器/Pod 生命周期、网络、文件系统、命令执行;
- CodeInterpreter 层(code_interpreter SDK):包裹一个已存在的 Sandbox 实例,在其之上提供多语言代码执行、执行上下文(Context)管理与变量持久化;
- 沙箱内运行时:code-interpreter 镜像内置 Jupyter kernel gateway,由 execd 守护进程统一对外提供代码执行 API(默认 execd 端口经
sandbox.get_endpoint(DEFAULT_EXECD_PORT)获取); - 服务端:
opensandbox-server接收 SDK 的创建请求,按 Provider(Docker 或 Kubernetes BatchSandbox)实际拉起工作负载。
CodeInterpreter.create(sandbox=sandbox)是唯一的工厂入口,它会先解析 execd 端点,然后执行双重严格健康检查(见下文“源码实现”一节),确认沙箱内 Jupyter 运行时真正就绪后才返回可用实例。这种“Sandbox 管基础设施、CodeInterpreter 管代码执行”的关注点分离,也是 code_interpreter.py 模块文档中明确的设计原则。
获取 Code Interpreter 镜像
Code Interpreter 依赖一个专用的预构建容器镜像,镜像中预装了 Python、Java、Go、Node.js 等多语言运行时。官方镜像源与环境定义维护在独立的 sandbox-images 仓库中。从镜像仓库拉取即可:
docker pull sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.1.0 # use docker hub # docker pull opensandbox/code-interpreter:v1.1.0注意:Code Interpreter SDK README 强调,必须使用
opensandbox/code-interpreter镜像(或其衍生镜像),普通python:3.11之类的裸镜像不含 Jupyter 运行时,无法通过 CodeInterpreter 的严格健康检查。
语言版本可以通过创建沙箱时注入环境变量选择,未设置时使用镜像默认版本:
| 语言 | 环境变量 | 示例值 |
|---|---|---|
| Python | PYTHON_VERSION | 3.11 |
| Java | JAVA_VERSION | 17 |
| Node.js | NODE_VERSION | 20 |
| Go | GO_VERSION | 1.24 |
启动本地 OpenSandbox 服务端(Docker Provider)
在 Docker 环境下启动本地服务端只需三步:
uv pip install opensandbox-server opensandbox-server init-config ~/.sandbox.toml --example docker opensandbox-serverinit-config --example docker会生成一份基于 Docker 运行时的示例配置~/.sandbox.toml,随后opensandbox-server启动并监听(示例脚本默认连接localhost:8080)。
创建并访问 Code Interpreter 沙箱
安装 SDK 后运行仓库内置示例:
# Install OpenSandbox packages uv pip install opensandbox opensandbox-code-interpreter # Run the example (requires SANDBOX_DOMAIN / SANDBOX_API_KEY) uv run python examples/code-interpreter/main.py示例脚本环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
SANDBOX_DOMAIN | localhost:8080 | 沙箱服务地址 |
SANDBOX_API_KEY | (可选) | 服务端开启鉴权时必填的 API key |
SANDBOX_IMAGE | sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.1.0 | 使用的沙箱镜像 |
示例代码逐段解析
main.py 的完整流程分为四步,核心代码结构如下:
import asyncio import os from datetime import timedelta from code_interpreter import CodeInterpreter, SupportedLanguage from opensandbox import Sandbox from opensandbox.config import ConnectionConfig async def main() -> None: domain = os.getenv("SANDBOX_DOMAIN", "localhost:8080") api_key = os.getenv("SANDBOX_API_KEY") image = os.getenv( "SANDBOX_IMAGE", "sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.1.0", ) # 1. 连接配置:域名 + 可选 API Key + 请求超时 config = ConnectionConfig( domain=domain, api_key=api_key, request_timeout=timedelta(seconds=60), ) # 2. 创建沙箱,entrypoint 指向镜像内的 code-interpreter 启动脚本 sandbox = await Sandbox.create( image, connection_config=config, entrypoint=["/opt/code-interpreter/code-interpreter.sh"] ) try: # 3. 包裹 CodeInterpreter(内部含 execd ping + Jupyter 端口探活) interpreter = await CodeInterpreter.create(sandbox=sandbox) # 4. 以 language 参数使用各语言的“默认上下文”,状态跨 run 持久化 py_exec = await interpreter.codes.run( "import platform\n" "print('Hello from Python!')\n" "result = {'py': platform.python_version(), 'sum': 2 + 2}\n" "result", language=SupportedLanguage.PYTHON, ) print("\n=== Python example ===") for msg in py_exec.logs.stdout: print(f"[Python stdout] {msg.text}") if py_exec.result: for res in py_exec.result: print(f"[Python result] {res.text}") # ... Java / Go / TypeScript 示例同理 finally: # 5. 无论成功与否都销毁远端实例,避免资源泄漏 await sandbox.destroy()几个关键实现点:
entrypoint=["/opt/code-interpreter/code-interpreter.sh"]:这是镜像内启动 Jupyter 运行时的入口脚本,缺少它沙箱内的解释器运行时不会启动,CodeInterpreter.create的严格健康检查会超时抛出SandboxReadyTimeoutException;language=SupportedLanguage.PYTHON而不是create_context:从 services/code.py 的run协议定义可知,当只传language而不传context时,execd 会为该语言创建或复用一个默认会话,因此同一语言多次run的变量状态可以跨执行持久化;models/code.py 中SupportedLanguage枚举定义了六种语言:PYTHON、JAVA、GO、TYPESCRIPT、BASH、JAVASCRIPT;- 结果结构:
Execution对象区分logs.stdout/logs.stderr(标准输出流)与result(代码最后一个表达式的求值结果)。Python 示例最后单独写一行result正是为了让解释器捕获{'py': '3.14.2', 'sum': 4}这个值,而print的内容进入 stdout; finally中await sandbox.destroy():官方文档特别指出,即使解释器初始化或代码执行抛异常,清理逻辑仍会执行,保证远端实例被终止。
运行后的典型输出为:
=== Python example === [Python stdout] Hello from Python! [Python result] {'py': '3.14.2', 'sum': 4} === Java example === [Java stdout] Hello from Java! [Java stdout] 2 + 3 = 5 [Java result] 5 === Go example === [Go stdout] Hello from Go! 3 + 4 = 7 === TypeScript example === [TypeScript stdout] Hello from TypeScript! [TypeScript stdout] sum = 6该示例还附带了 test_main.py 作为测试入口,可结合 SDK 自身测试(如 test_code_service_adapter_streaming.py)理解流式输出与请求适配层的实现。
扩展用法:上下文隔离、流式输出与同步 API
除示例脚本外,SDK README 还覆盖了以下能力,均为同一套interpreter.codes服务:
- 显式上下文:
await interpreter.codes.create_context(SupportedLanguage.PYTHON)创建独立会话,不同语言上下文相互隔离(多语言互不串状态); - 流式输出:通过
ExecutionHandlers(on_stdout=..., on_stderr=...)实时处理逐行输出,适合长任务; - 同步 API:
SandboxSync+CodeInterpreterSync+ConnectionConfigSync组合提供非 asyncio 的等价实现; - 运行时安装依赖:
await sandbox.commands.run("pip install pandas numpy")可直接在沙箱内装包,随后在代码中 import 使用。
从 Pool 池获取 Code Interpreter 沙箱(Kubernetes)
在 Kubernetes 场景下,冷启动一个 Pod 需要拉镜像、起容器。OpenSandbox 提供 Pool 资源池机制:预先创建并保活一批“热 Pod”,生命周期 API 直接从池中分配,跳过容器冷启动。
启动 k8s OpenSandbox 服务端
uv pip install opensandbox-server # replace with your k8s cluster config, kubeconfig etc. opensandbox-server init-config ~/.sandbox.toml --example k8s curl -o ~/batchsandbox-template.yaml https://raw.githubusercontent.com/opensandbox-group/OpenSandbox/main/server/opensandbox_server/examples/example.batchsandbox-template.yaml opensandbox-serverBatchSandbox 模板文件在仓库中同样有本地副本:example.batchsandbox-template.yaml,可直接查看而非依赖远程下载。服务端 k8s 示例配置可参考 example.config.k8s.toml。
创建 Pool 资源
以下 Pool 声明来自官方示例文档,它定义了池容量水位(bufferMin/bufferMax与poolMin/poolMax)以及一个三阶段启动模板。Pool CRD 的另一种样例见 sandbox_v1alpha1_pool.yaml:
apiVersion: sandbox.opensandbox.io/v1alpha1 kind: Pool metadata: labels: app.kubernetes.io/name: sandbox-k8s app.kubernetes.io/managed-by: kustomize name: pool-sample namespace: opensandbox spec: template: metadata: labels: app: example spec: volumes: - name: sandbox-storage emptyDir: { } - name: opensandbox-bin emptyDir: { } initContainers: - name: task-executor-installer image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/task-executor:v0.1.0 command: [ "/bin/sh", "-c" ] args: - | cp /workspace/server /opt/opensandbox/task-executor && chmod +x /opt/opensandbox/task-executor volumeMounts: - name: opensandbox-bin mountPath: /opt/opensandbox - name: execd-installer image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/execd:v1.1.0 command: [ "/bin/sh", "-c" ] args: - | cp ./execd /opt/opensandbox/execd && cp ./bootstrap.sh /opt/opensandbox/bootstrap.sh && chmod +x /opt/opensandbox/execd && chmod +x /opt/opensandbox/bootstrap.sh volumeMounts: - name: opensandbox-bin mountPath: /opt/opensandbox containers: - name: sandbox image: sandbox-registry.cn-zhangjiakou.cr.aliyuncs.com/opensandbox/code-interpreter:v1.1.0 command: - "/bin/sh" - "-c" - | /opt/opensandbox/task-executor \ -listen-addr=0.0.0.0:5758 \ -log-dir=/tmp env: - name: SANDBOX_MAIN_CONTAINER value: main - name: EXECD_ENVS value: /opt/opensandbox/.env - name: EXECD value: /opt/opensandbox/execd volumeMounts: - name: sandbox-storage mountPath: /var/lib/sandbox - name: opensandbox-bin mountPath: /opt/opensandbox tolerations: - operator: "Exists" capacitySpec: bufferMax: 3 bufferMin: 1 poolMax: 5 poolMin: 0Pool 模式的 entrypoint 注入机制
这是 Pool 方案中最容易误解的部分,官方文档给出了明确的机制说明:
生命周期 API 分配的是 Pool 中已经在运行的 Pod,因此它不会替换该 Pod 的command、args或env。当创建请求携带entrypoint或环境变量时,服务端把它们记录到BatchSandbox.spec.taskTemplate中;Controller 随后再通过 Pod IP 的5758 端口把任务下发给 Pod 内的 task-executor 执行。
因此 Pool 模板必须自行提供完整执行链路:
- 安装并前台运行 task-executor,监听
0.0.0.0:5758,并显式指定-log-dir使排查路径确定(示例写/tmp,日志落在/tmp/task-executor.log); - 在 Pod 启动前安装 execd 与 bootstrap.sh到共享卷
/opt/opensandbox(由上面的两个 initContainer 完成); bootstrap.sh必须保持在/opt/opensandbox/bootstrap.sh,因为服务端生成的任务会调用这个固定路径;execd 二进制可以用其他路径,前提是 task-executor 环境中通过EXECD变量正确指向;- 分配后由 bootstrap.sh 启动 execd,这样
EXECD_ACCESS_TOKEN等请求级变量才可用——这正是示例把 task-executor 而非业务进程留作热 Pod 前台进程的原因。
由此可以推断:Pod YAML 里始终显示 Pool 模板是预期行为,排查时应该看BatchSandbox资源与 task-executor,而不是 Pod 定义。官方给出的排查命令序列:
# Confirm that the server injected the requested process and environment. kubectl get batchsandbox <sandbox-name> -n <namespace> \ -o jsonpath='{.spec.taskTemplate}{"\n"}' # Find the allocated Pod. The annotation value contains a JSON `pods` array. kubectl get batchsandbox <sandbox-name> -n <namespace> \ -o jsonpath='{.metadata.annotations.sandbox\.opensandbox\.io/alloc-status}{"\n"}' # Replace <pool-pod> with the first Pod name from that array. kubectl exec <pool-pod> -n <namespace> -- \ sh -c 'test -x /opt/opensandbox/task-executor && test -x /opt/opensandbox/bootstrap.sh' kubectl exec <pool-pod> -n <namespace> -- \ tail -n 100 /tmp/task-executor.log # Check the executor health endpoint from a second terminal while this runs. kubectl port-forward pod/<pool-pod> -n <namespace> 5758:5758 curl http://127.0.0.1:5758/health curl http://127.0.0.1:5758/getTasks # The lifecycle server uses <sandbox-name>-0 as the task name. Check the task's # captured output (adjust the path if task-executor uses a custom data directory). kubectl exec <pool-pod> -n <namespace> -- \ sh -c 'tail -n 100 /var/lib/sandbox/tasks/<sandbox-name>-0/stdout.log; tail -n 100 /var/lib/sandbox/tasks/<sandbox-name>-0/stderr.log' # Check controller logs for delivery failures between the controller and port 5758. kubectl logs -n opensandbox-system -l control-plane=controller-manager --tail=100一个关键的故障排查提示:如果taskTemplate已存在但健康检查连不上 5758 端口,先确认 task-executor 已安装且仍在运行。由于生成的任务是在后台启动bootstrap.sh的,即使bootstrap.sh缺失或请求的 entrypoint 后续失败,任务包装器也可能报告成功——所以不要仅依赖taskFailed或taskLastErrorMessage判断这类失败,应直接检查任务的stderr.log/stdout.log并核实 execd 或应用进程本身。
运行 Pool 示例
main_use_pool.py 与单实例版本的关键差异在于Sandbox.create的三个参数:
sandbox = await Sandbox.create( image, connection_config=config, extensions={"poolRef":"pool-sample"}, # 引用上面创建的 Pool entrypoint=["/opt/code-interpreter/code-interpreter.sh"], env={"TEST_ENV": "test"}, # 请求级环境变量,经 taskTemplate 注入 )随后脚本先用一段 Python 代码验证TEST_ENV是否成功注入到沙箱内,再依次执行 Java、Go、TypeScript 示例,最后调用await sandbox.kill()归还池资源。运行方式:
uv pip install opensandbox opensandbox-code-interpreter uv run python examples/code-interpreter/main_use_pool.pyPool 示例的典型输出(注意第一段是环境变量验证):
=== Verify Environment Variable === [ENV Check] TEST_ENV value: test [ENV Result] 'test' === Java example === [Java stdout] Hello from Java! [Java stdout] 2 + 3 = 5 [Java result] 5 === Go example === [Go stdout] Hello from Go! 3 + 4 = 7 === TypeScript example === [TypeScript stdout] Hello from TypeScript! [TypeScript stdout] sum = 6源码实现佐证
结合服务端源码,可以对上述机制做三点印证:
poolRef仅 Kubernetes Provider 支持。docker_service.py 中明确校验:请求携带extensions.poolRef时,Docker provider 会直接拒绝并提示 "poolRef is not supported by the Docker provider. Use Kubernetes BatchSandbox provider instead";kubernetes_service.py 则负责校验 Pool 是否存在,并限制 pooled 场景不能与networkPolicy同时使用(因为池 Pod 是预创建的)。这也解释了为什么 Pool 示例必须走 k8s 服务端。- 严格健康检查的实现。code_interpreter.py 中定义了
RUNTIME_PROCESS_CHECK_COMMAND(L52-L55):CodeInterpreter.create的健康检查包含两步——execd 守护进程响应GET /ping,且通过 execd 命令 API 探测沙箱内 Jupyter 监听端口(127.0.0.1:${JUPYTER_PORT:-44771},默认 44771)是否可连接。注释解释得很直接:execd 在 entrypoint 启动 Jupyter 之前就开始服务/ping,仅凭守护进程 ping 无法证明解释器运行时就绪;默认ready_timeout为 30 秒、轮询间隔 200 毫秒,可用skip_health_check=True关闭。 - 执行上下文的数据模型。models/code.py 中
CodeContext只含id与language两个字段,语言字段经校验器保证非空;省略context.id即触发 execd 侧的“默认会话”语义,这与示例脚本只传language=的写法一一对应。
适用前提与参考
- 本地(Docker)路径要求宿主机可运行 Docker,且能拉取上述 code-interpreter 镜像;k8s 路径要求已部署 OpenSandbox operator(Pool/BatchSandbox CRD 与 controller);
SANDBOX_DOMAIN指向的服务端必须与沙箱 Provider 匹配:Docker 服务端走--example docker配置,Pool 场景必须走--example k8s配置;- 镜像中各语言的具体版本以 sandbox-images 仓库的环境文档为准,本文涉及的
v1.1.0镜像版本以仓库文档与示例代码为准。
关键参考路径:
- 本文档原始来源:docs/examples/code-interpreter.md
- 示例脚本:main.py、main_use_pool.py
- Python Code Interpreter SDK:code_interpreter.py、README.md
- 服务端 Pool 校验逻辑:kubernetes_service.py、docker_service.py
- BatchSandbox 模板示例:example.batchsandbox-template.yaml
【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考