OpenSandbox Kotlin/Java SDK 实战指南:沙箱生命周期、命令流式执行、文件操作与客户端池化
2026/9/14 3:33:17 网站建设 项目流程

OpenSandbox Kotlin/Java SDK 实战指南:沙箱生命周期、命令流式执行、文件操作与客户端池化

【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox

OpenSandbox 面向 AI Agent 场景提供了多语言 SDK,其中 Kotlin SDK(同时可直接被 Java 调用)是连接 OpenSandbox Server、创建并管理安全沙箱的核心入口。本篇基于 Kotlin/Java SDK 官方文档 与仓库中sdks/sandbox/kotlin/的实际源码,完整覆盖安装、快速上手、生命周期钩子、命令/文件操作、连接与重试配置、出口网络策略和 Credential Vault,以及实验性的客户端侧SandboxPool池化机制,帮助你在 Java/Kotlin 应用中以可复制、可运行的方式接入 OpenSandbox。

1. 安装

Kotlin SDK 以com.alibaba.opensandbox:sandbox坐标发布,Gradle(Kotlin DSL)与 Maven 两种方式均可引入:

// Gradle (Kotlin DSL) dependencies { implementation("com.alibaba.opensandbox:sandbox:{latest_version}") }
<!-- Maven --> <dependency> <groupId>com.alibaba.opensandbox</groupId> <artifactId>sandbox</artifactId> <version>{latest_version}</version> </dependency>

如果需要分布式部署客户端池,仓库还包含可选模块sandbox-pool-redis(对应 Maven 坐标com.alibaba.opensandbox:sandbox-pool-redis),其实现位于 RedisPoolStateStore.kt;此外同目录下的code-interpreter子模块提供代码解释器的高层封装 CodeInterpreter.kt。

2. 快速上手:创建沙箱并执行命令

前提:运行示例前需保证 OpenSandbox 服务已启动,启动方式见 Getting Started。

import com.alibaba.opensandbox.sandbox.Sandbox; import com.alibaba.opensandbox.sandbox.config.ConnectionConfig; import com.alibaba.opensandbox.sandbox.domain.exceptions.SandboxException; import com.alibaba.opensandbox.sandbox.domain.models.execd.executions.Execution; public class QuickStart { public static void main(String[] args) { // 1. Configure connection ConnectionConfig config = ConnectionConfig.builder() .domain("api.opensandbox.io") .apiKey("your-api-key") .build(); // 2. Create a Sandbox using try-with-resources try (Sandbox sandbox = Sandbox.builder() .connectionConfig(config) .image("ubuntu") .build()) { // 3. Execute a shell command Execution execution = sandbox .commands() .run("echo 'Hello Sandbox!'"); // 4. Print output System.out.println(execution.getLogs().getStdout().get(0).getText()); // 5. Cleanup (sandbox.close() called automatically) // Note: kill() must be called explicitly if you want to terminate the remote sandbox instance immediately sandbox.kill(); } catch (SandboxException e) { // Handle Sandbox specific exceptions System.err.println("Sandbox Error: [" + e.getError().getCode() + "] " + e.getError().getMessage()); System.err.println("Request ID: " + e.getRequestId()); } catch (Exception e) { e.printStackTrace(); } } }

从源码结构看,Sandbox类是整个 SDK 的主入口,见 Sandbox.kt:它是一个AutoCloseable,构造函数聚合了Sandboxes(生命周期)、FilesystemCommandsHealthMetricsEgressCredentialVaultIsolationServiceDiagnostics等服务对象,并支持可选的customHealthCheck回调。因此sandbox.close()只负责清理客户端资源,远程沙箱实例必须通过显式kill()终止——这正是示例中两者并列出现的原因。异常处理上,SandboxException携带error.codeerror.messagerequestId,方便与服务端日志对账。

3. 生命周期钩子(Lifecycle Hooks)

可以在Sandbox.Builder上配置生命周期钩子:preStart在 entrypoint 启动前完成,periodic钩子在启动完成后按调度周期执行。

import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.LifecycleHook; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.PeriodicLifecycleHook; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.SandboxLifecycle; SandboxLifecycle lifecycle = SandboxLifecycle.builder() .preStart(LifecycleHook.builder() .command("sh", "-c", "echo ready > /tmp/prestart.done") .timeoutSeconds(120) .build()) .periodic(PeriodicLifecycleHook.builder() .name("checkpoint") .schedule("@every 5m") .command("sh", "-c", "date -u >> /tmp/checkpoints.log") .timeoutSeconds(120) .build()) .build(); Sandbox sandbox = Sandbox.builder() .connectionConfig(config) .image("ubuntu:24.04") .lifecycle(lifecycle) .build();

超时约束由 Server 端校验:preStart接受 1–10800 秒,periodic接受 1–300 秒,两者缺省均为 60 秒。这一点可以在服务端 Schema 中得到印证,schema.py 中timeoutSeconds字段分别声明了ge=1, le=10800(preStart)与ge=1, le=300(periodic)。关于触发时机、失败行为与运行时支持范围的完整说明,见 Lifecycle Hooks 指南。

4. 使用示例

4.1 生命周期管理:续期、暂停与恢复

// Renew the sandbox // This resets the expiration time to (current time + duration) sandbox.renew(Duration.ofMinutes(30)); // Pause execution (suspends all processes) sandbox.pause(); // Resume execution sandbox.resume(); // Get current status SandboxInfo info = sandbox.getInfo(); System.out.println("State: " + info.getStatus().getState()); System.out.println("Expires: " + info.getExpiresAt()); // null when manual cleanup mode is used

renew(timeout)的语义是把过期时间重置为“当前时间 + duration”,对应 Sandbox.kt 中的renew(timeout: Duration)实现。若希望创建永不过期(手动清理模式)的沙箱,传入timeout(null)即可,此时getInfo().getExpiresAt()返回 null:

Sandbox manual = Sandbox.builder() .connectionConfig(config) .image("ubuntu") .timeout(null) .build();

注意 Builder 的默认值并非无穷大:从 Sandbox.kt 可以看到timeout默认Duration.ofSeconds(600)(即 10 分钟),readyTimeout默认Duration.ofSeconds(30),健康检查轮询间隔healthCheckPollingInterval默认 200 ms——这与文档中“超时默认 10 分钟、就绪等待默认 30 秒”的说明一致。

4.2 自定义健康检查

默认的 ready 检查是 ping;你也可以传入 lambda 覆盖判断逻辑(例如等待某个端口可访问)。注意:自定义检查内部的超时需要你自行控制,SDK 无法中途打断它。

Sandbox sandbox = Sandbox.builder() .connectionConfig(config) .image("nginx:latest") // Custom check: Wait for port 80 to be accessible .healthCheck(sbx -> { try { // 1. Get the external mapped address for port 80 SandboxEndpoint endpoint = sbx.getEndpoint(80); // 2. Perform your connection check (e.g. HTTP request, Socket connect) // return checkConnection(endpoint.getEndpoint()); return true; } catch (Exception e) { return false; } }) .build();

getEndpoint(port)解析的是沙箱端点的对外可达地址;SDK 内部对 execd 与 egress 分别使用默认端口 44772 与 18080(见 Constants.kt)。

4.3 命令执行与流式输出

通过ExecutionHandlers可以实时消费 stdout/stderr 与完成事件:

// Create handlers for streaming output ExecutionHandlers handlers = ExecutionHandlers.builder() .onStdout(msg -> System.out.println("STDOUT: " + msg.getText())) .onStderr(msg -> System.err.println("STDERR: " + msg.getText())) .onExecutionComplete(complete -> System.out.println("Command finished in " + complete.getExecutionTimeInMillis() + "ms") ) .build(); // Execute command with handlers RunCommandRequest request = RunCommandRequest.builder() .command("for i in {1..5}; do echo \"Count $i\"; sleep 0.5; done") .handlers(handlers) .build(); sandbox.commands().run(request);

如果不想走 shell 解析、以 argv 形式原生执行程序,可以直接传参数列表。在 Linux 上,下面的示例会原样打印字面量$HOME,并保持hello world为单个参数:

sandbox.commands().run(RunCommandRequest.builder() .argv(List.of("printf", "%s\n", "$HOME", "hello world")) .build());

原生 argv 执行依赖更新版本的 execd,可执行文件查找与平台行为见 execd 命令执行模式说明。需要留意的是:SSE/流式请求会绕过 SDK 的自动重试(下文第 5.2 节),因为流式请求体无法安全重放。

4.4 文件操作:写、读、搜索、删除

sandbox.files()覆盖了写文件、读文件、按模式搜索和批量删除:

// 1. Write file sandbox.files().write(List.of( WriteEntry.builder() .path("/tmp/hello.txt") .data("Hello World") .mode(644) .build() )); // 2. Read file String content = sandbox.files().readFile("/tmp/hello.txt", "UTF-8", null); System.out.println("Content: " + content); // 3. List/Search files List<EntryInfo> files = sandbox.files().search( SearchEntry.builder() .path("/tmp") .pattern("*.txt") .build() ); files.forEach(f -> System.out.println("Found: " + f.getPath())); // 4. Delete file sandbox.files().deleteFiles(List.of("/tmp/hello.txt"));

文件服务的接口定义位于 Filesystem.kt,write采用WriteEntry列表支持批量写入并可为每个文件单独指定mode

4.5 管理面操作(SandboxManager)

SandboxManager用于管理面任务:列出既有沙箱、按状态过滤、批量终止等。

SandboxManager manager = SandboxManager.builder() .connectionConfig(config) .build(); import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.SandboxState; // ... // List running sandboxes PagedSandboxInfos sandboxes = manager.listSandboxInfos( SandboxFilter.builder() .states(SandboxState.RUNNING) .pageSize(10) .page(1) .build() ); sandboxes.getSandboxInfos().forEach(info -> { System.out.println("Found sandbox: " + info.getId()); // Perform admin actions manager.killSandbox(info.getId()); }); // Try-with-resources will automatically call manager.close() // manager.close();

管理类实现见 SandboxManager.kt,它同样实现了AutoCloseable,建议放入 try-with-resources 中。

4.6 客户端侧沙箱池(SandboxPool,实验特性)

SandboxPool在客户端维护一个“已就绪”沙箱的闲置缓冲区,从而把冷启动成本前置,降低acquire()的获取延迟。

⚠ 实验特性:SandboxPool仍在根据生产反馈快速演进,后续版本可能引入不兼容变更。

基础用法:

import com.alibaba.opensandbox.sandbox.pool.SandboxPool; import com.alibaba.opensandbox.sandbox.pool.SandboxPoolManager; import com.alibaba.opensandbox.sandbox.domain.pool.PoolCreationSpec; import com.alibaba.opensandbox.sandbox.domain.pool.PoolDestroyOptions; import com.alibaba.opensandbox.sandbox.domain.pool.AcquirePolicy; import com.alibaba.opensandbox.sandbox.infrastructure.pool.InMemoryPoolStateStore; SandboxPool pool = SandboxPool.builder() .poolName("demo-pool") .ownerId("worker-1") .maxIdle(3) .warmupCreateQps(10) .warmupConcurrency(128) .warmupReadyTimeout(Duration.ofSeconds(45)) .warmupHealthCheckInitialDelay(Duration.ofSeconds(2)) .stateStore(new InMemoryPoolStateStore()) // single-node store .connectionConfig(config) .creationSpec( PoolCreationSpec.builder() .image("ubuntu:22.04") .entrypoint(java.util.List.of("tail", "-f", "/dev/null")) .extension("storage.id", "dataset-001") .build() ) .build(); pool.start(); Sandbox sb = pool.acquire(Duration.ofMinutes(10), AcquirePolicy.FAIL_FAST); try { sb.commands().run("echo pool-ok"); } finally { sb.kill(); sb.close(); } pool.shutdown(true);
分阶段预热调度

Kotlin 版本的池化以固定的 1 秒节奏做 reconcile(reconcileInterval(...)API 已被移除;源码中该节奏由 SandboxPool.kt 的RECONCILE_INTERVAL_MS = 1_000L常量固定)。在此节奏下:

  • warmupCreateQps(...)(默认10)限制每个 tick 允许的新预热创建数;
  • warmupConcurrency(...)(默认128)独立限制创建后的健康检查与 prepare 并发度;
  • 内置的预热创建只做一次 HTTP 尝试,不遵循常规传输重试策略,也不对 HTTP 429 做特殊节流;自定义PooledSandboxCreator必须使用context.createConnectionConfig并尊重context.skipHealthCheck以保持这些语义;acquire()触发的直接创建行为不变。

创建后的流水线是显式分阶段的:

  1. 创建一个沙箱(不经过 Builder 的内联就绪等待循环);
  2. 等待warmupHealthCheckInitialDelay(默认 0)后,每warmupHealthCheckPollingInterval(默认 500 ms)检查一次就绪,直到warmupReadyTimeout(默认 30 s);到期时仍会做最后一次检查;
  3. 执行一次warmupSandboxPreparer;若配置了warmupPostPrepareHealthCheck,则按相同轮询间隔重试,直到warmupPostPrepareHealthCheckTimeout(默认 30 s),且不会重跑 preparer;
  4. 续期沙箱 TTL 并把 ID 提交进闲置缓冲区。

诊断状态方面:degradedThreshold(默认3)仍控制HEALTHY → DEGRADED的诊断状态,但 Kotlin 实现不再使用指数退避暂停补池,snapshot().backoffActive恒为false

AcquirePolicy 语义

AcquirePolicy决定“闲置缓冲区为空”或“首个闲置候选未通过就绪检查”时的行为:

策略跨闲置候选重试耗尽后兜底
FAIL_FASTPoolEmptyException/PoolAcquireFailedException
DIRECT_CREATE(默认)通过 lifecycle API 直接创建新沙箱
RETRY_NEXT_IDLE最多尝试maxAcquireRetries个闲置沙箱抛异常
RETRY_NEXT_IDLE_THEN_CREATE最多尝试maxAcquireRetries个闲置沙箱直接创建新沙箱

当池内可能混有健康与陈旧沙箱时(例如冷启动很慢的自定义模板、网络抖动遗留的不可达闲置实例),建议选用RETRY_NEXT_IDLE*变体。每个失败候选最多消耗acquireReadyTimeout,因此要用maxAcquireRetries(默认3)限定重试次数。

池生命周期语义
  • acquire()仅允许在池状态为RUNNING时调用;
  • 状态为DRAINING/STOPPED时,acquire()PoolNotRunningException
  • 池命名空间正在销毁或已销毁时,acquire()PoolDestroyedException,且不会回退到直接创建;
  • maxIdle是“就绪闲置沙箱”的目标/上限,不是对借出沙箱或AcquirePolicy.DIRECT_CREATE所建沙箱的全局上限;
  • ownerId是锁持有者标识(节点/进程 ID),并非池标识;省略时 SDK 自动生成基于 UUID 的默认值;
  • 需要在“预热就绪成功后、进入闲置池之前”做准备工作时使用warmupSandboxPreparer(...);若 prepare 后的服务需要独立验证窗口,再加warmupPostPrepareHealthCheck(...),重试不会重跑 preparer。
预热性能观测

为追踪预热路径,启用ConnectionConfig.builder().enableTracing(true)并在应用中加入 OpenTelemetry SDK 与 exporter。每次预热会产生一条 trace(pool.warmup根 span,外加create/readiness_check/prepare/post_prepare_check/renew/commit各阶段 span),并把trace_id/span_id发布到 SLF4J MDC,因此可以通过sandbox_id在日志中检索对应预热过程。详细设计见 SDK Tracing(Pool Warmup)。

分布式部署

分布式部署时,使用可选的com.alibaba.opensandbox:sandbox-pool-redis模块,或自行实现PoolStateStore接口。Redis 模块接收调用方管理的 Jedis 客户端,Redis 连接的配置与生命周期仍归你的应用所有。共享同一池命名空间的节点必须使用相同的沙箱创建与预热定义;修改该定义时应更换poolName或命名空间。Kotlin 实现会在独立于分阶段预热的节奏上续租主锁,间隔不大于primaryLockTtl的三分之一;若提交前租约 epoch 变化,任务会被丢弃。

分布式模式下的补充行为:

  • resize(maxIdle)可在任意节点调用;调用在目标值写入共享状态库后即返回,当前主节点在周期性 reconcile 中执行补池或收缩。需要排空分布式闲置缓冲区时用resize(0)并等待snapshot().idleCount == 0releaseAllIdle()只是尽力而为的清理。
  • releaseAllIdle()保持串行清理;releaseAllIdle(concurrency)提供有界并行清理,concurrency必须为正数,且该重载会等待每个排空 ID 都完成尽力而为的 kill 尝试。
  • SandboxPoolManager.destroy(poolName)是更强的管理操作:写入DESTROYING围栏、排空可见闲置 ID、尽力 kill 闲置沙箱、清理持久化池状态,最后写入带 TTL 的DESTROYED墓碑以防止旧节点重建同名池命名空间。若排空或持久状态清理无法完成,destroy()PoolDestroyIncompleteException并将命名空间保持DESTROYING围栏状态;重试destroy()可继续完成清理。

无需构造旧SandboxPool对象即可销毁旧池命名空间的运维示例:

SandboxPoolManager poolManager = SandboxPoolManager.builder() .stateStore(redisStore) .connectionConfig(config) .ownerId("deploy-job-123") .build(); poolManager.destroy( "old-pool", new PoolDestroyOptions() );

池化的核心实现分布在 SandboxPool.kt、SandboxPoolManager.kt 与 pool 领域模型目录,测试覆盖了限流、共享连接、异步预热等场景(如 SandboxPoolRateLimitTest.kt)。

5. 配置详解

5.1 连接配置(ConnectionConfig)

ConnectionConfig管理 API Server 的连接参数,完整参数表如下(含环境变量的对应关系):

参数说明默认值环境变量
apiKey鉴权用 API Key必填OPEN_SANDBOX_API_KEY
domain沙箱服务端点域名必填(或 localhost:8080)OPEN_SANDBOX_DOMAIN
protocolHTTP 协议(http/https)http-
requestTimeoutAPI 请求超时30 秒-
debug开启 HTTP 请求调试日志false-
headers自定义 HTTP 头-
connectionPool共享的 OkHttp ConnectionPoolSDK 按实例自建-
retryPolicy非流式请求的自动重试策略(见 自动重试)启用(RetryPolicy()-
useServerProxy以沙箱 Server 为 execd/endpoint 请求的代理(客户端无法直连沙箱时使用)false-
disableMetrics禁用 SDK 创建延迟遥测(见 SDK Telemetry)falseOPENSANDBOX_DISABLE_METRICS
enableTracing为池预热启用 OpenTelemetry 追踪(见 SDK Tracing)false-

环境变量回退逻辑在源码中可直接确认,ConnectionConfig.kt 定义了OPEN_SANDBOX_API_KEYOPEN_SANDBOX_DOMAINOPENSANDBOX_DISABLE_METRICS三个常量,Builder 未显式设置apiKey/domain时按此回退。

// 1. Basic configuration ConnectionConfig config = ConnectionConfig.builder() .apiKey("your-key") .domain("api.opensandbox.io") .requestTimeout(Duration.ofSeconds(60)) .build(); // 2. Advanced: Shared Connection Pool // If you create many Sandbox instances, sharing a connection pool is recommended to save resources. // SDK default keep-alive is 30 seconds for its own pools. ConnectionPool sharedPool = new ConnectionPool(50, 30, TimeUnit.SECONDS); ConnectionConfig sharedConfig = ConnectionConfig.builder() .apiKey("your-key") .domain("api.opensandbox.io") .headers(Map.of( "X-Custom-Header", "value", "X-Request-ID", "trace-123" )) .connectionPool(sharedPool) // Inject shared pool .build();

SDK 遥测说明:Sandbox.builder()...build()默认会把创建延迟上报到POST /v1/metrics/events。调用ConnectionConfig.builder().disableMetrics(true)或导出OPENSANDBOX_DISABLE_METRICS=1可关闭,详见 SDK Telemetry。

5.2 自动重试

SDK 会自动重试瞬时故障:ConnectionConfig会在 SDK 的非流式 HTTP 客户端上安装RetryInterceptor(策略类型为com.alibaba.opensandbox.sandbox.transport.RetryPolicy)。

默认行为:

  • 默认启用。幂等方法(GET/HEAD/PUT/DELETE/OPTIONS)在429502503以及发送前传输失败(DNS、TCP 连接、TLS 握手)时重试;
  • POST/PATCH默认不会因状态码重试(请求可能已在服务端生效);但发送前传输失败(尚未写出任何字节)仍会重试;
  • 最多3次重试,采用 decorrelated-jitter 指数退避,并尊重服务端Retry-After头(上限 60 s);
  • SSE/流式请求完全绕过自动重试,因为其响应体无法安全重放。SSE 客户端同时禁用 OkHttp 内置连接恢复,防止流式命令 POST 被重放。

这些默认值在 RetryPolicy.kt 中可以直接核对:maxRetries默认DEFAULT_MAX_RETRIES = 3initialBackoff默认 500 ms、maxBackoff默认 30 s、jitter默认JitterMode.DECORRELATED,另有可选的perAttemptTimeoutoverallDeadline;RetryDecision.kt 与 RetryInterceptor.kt 分别实现退避计算与“更紧的单次/整体超时”的裁决逻辑。

行为变更提示:SDK 策略重试默认开启,相比更早的 SDK 版本会提高 HTTP 尝试次数与尾延迟。如需关闭,使用RetryPolicy.disabled(),非流式请求将回退到 OkHttp 原有的内置连接恢复。

import com.alibaba.opensandbox.sandbox.transport.RetryPolicy; import com.alibaba.opensandbox.sandbox.transport.StatusCode; import java.time.Duration; import java.util.Set; // Disable SDK-policy retries and retain OkHttp's built-in connection recovery. ConnectionConfig config = ConnectionConfig.builder() .apiKey("your-key") .domain("api.opensandbox.io") .retryPolicy(RetryPolicy.disabled()) .build(); // Custom policy: more retries, an overall wall-clock deadline, and an opt-in to // retry POST/PATCH on 503 (only safe if your endpoints are idempotent). ConnectionConfig tuned = ConnectionConfig.builder() .apiKey("your-key") .domain("api.opensandbox.io") .retryPolicy(new RetryPolicy( /* maxRetries */ 5, /* initialBackoff */ Duration.ofMillis(500), /* maxBackoff */ Duration.ofSeconds(30), /* backoffMultiplier */ 2.0, /* jitter */ com.alibaba.opensandbox.sandbox.transport.JitterMode.DECORRELATED, /* retryableStatusCodesIdempotent */ RetryPolicy.DEFAULT_IDEMPOTENT_STATUS, /* retryableStatusCodesNonIdempotent */ Set.of(StatusCode.SERVICE_UNAVAILABLE), /* perAttemptTimeout */ null, /* overallDeadline */ Duration.ofSeconds(20), /* onRetry */ null)) .build();

重试行为有专门的单测保障,如 RetryPolicyTest.kt 与 RetryInterceptorTest.kt。

5.3 沙箱创建配置

Sandbox.builder()支持的创建参数及默认值:

参数说明默认值
imageDocker 镜像必填
timeout自动终止超时10 分钟
entrypoint容器 entrypoint 命令["tail", "-f", "/dev/null"]
resourceCPU 与内存限制{"cpu": "1", "memory": "2Gi"}
env环境变量
metadata自定义元数据标签
extensions透传给服务端的扩展参数
networkPolicy可选的出口网络策略(egress)-
credentialProxy可选的 Credential Vault 代理启动配置-
readyTimeout等待沙箱就绪的最长时间30 秒

注意:opensandbox.io/前缀的 metadata key 是系统保留标签,服务端会拒绝此类自定义 metadata。

完整示例(含出口网络策略):

import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.NetworkPolicy; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.NetworkRule; Sandbox sandbox = Sandbox.builder() .connectionConfig(config) .image("python:3.11") .timeout(Duration.ofMinutes(30)) .resource(map -> { map.put("cpu", "2"); map.put("memory", "4Gi"); }) .env("PYTHONPATH", "/app") .metadata("project", "demo") .extension("storage.id", "dataset-001") .networkPolicy( NetworkPolicy.builder() .defaultAction(NetworkPolicy.DefaultAction.DENY) .addEgress( NetworkRule.builder() .action(NetworkRule.Action.ALLOW) .target("pypi.org") .build() ) .build() ) .build();

Builder 中readyTimeout还带参数校验:必须为正数,否则抛出异常(见 Sandbox.kt)。

5.4 运行时出口策略更新

运行时的 egress 读取与 patch 直连沙箱的 egress sidecar:SDK 先解析沙箱 18080 端口的 endpoint,再调用 sidecar 的/policyAPI。Patch 采用合并语义:

  • 传入规则优先于同target的既有规则;
  • 其他target的既有规则保持不变;
  • 单个 patch 载荷内部,同一target的第一条规则生效;
  • 当前defaultAction保持不变。
NetworkPolicy policy = sandbox.getEgressPolicy(); sandbox.patchEgressRules( List.of( NetworkRule.builder().action(NetworkRule.Action.ALLOW).target("www.github.com").build(), NetworkRule.builder().action(NetworkRule.Action.DENY).target("pypi.org").build() ) );

sidecar 侧的策略服务器实现见 policy_server.go 与 policy 包。

5.5 Credential Vault

Credential Vault 让 egress sidecar 在出站时注入凭证,从而把真实密钥排除在沙箱环境变量、命令、文件和日志之外。用法:创建沙箱时设置credentialProxyEnabled(true),再通过sandbox.credentialVault()写入凭证与绑定关系。

import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.Credential; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.CredentialAuth; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.CredentialBinding; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.CredentialMatch; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.CredentialVaultCreateRequest; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.NetworkPolicy; import com.alibaba.opensandbox.sandbox.domain.models.sandboxes.NetworkRule; import java.util.List; Sandbox sandbox = Sandbox.builder() .connectionConfig(config) .image("python:3.11") .networkPolicy( NetworkPolicy.builder() .defaultAction(NetworkPolicy.DefaultAction.DENY) .addEgress( NetworkRule.builder() .action(NetworkRule.Action.ALLOW) .target("api.example.com") .build() ) .build() ) .credentialProxyEnabled(true) .build(); sandbox.credentialVault().create( CredentialVaultCreateRequest.builder() .credentials( List.of( Credential.builder() .name("api-token") .inlineSource("<token>") .build() ) ) .bindings( List.of( CredentialBinding.builder() .name("api-token") .match( CredentialMatch.builder() .schemes(CredentialMatch.Scheme.HTTPS) .hosts("api.example.com") .paths("/v1/*") .build() ) .auth(CredentialAuth.apiKey("x-api-key", "api-token")) .build() ) ) .build() );

凭证匹配由CredentialMatch(scheme/host/path 三元组)与CredentialAuth(如apiKey(header, credentialName))共同决定。更完整的鉴权类型、绑定建议以及 Git/curl 示例见 Credential Vault 指南;sidecar 侧的凭证注入实现位于 credentialvault 包。

6. 验证与深入路径

  • 端到端:仓库tests/java/目录提供 Java E2E 套件(生命周期、命令、文件系统、池化、Credential Vault、错误处理等),可作为行为基准参照;
  • 单元/集成测试:Kotlin SDK 自身测试集中在sdks/sandbox/kotlin/sandbox/src/test/kotlin/,例如 SandboxTest.kt、SandboxManagerTest.kt、InMemoryPoolStateStoreTest.kt;
  • 服务端行为:生命周期钩子的超时校验、egress/policyAPI 与 metrics 上报端点分别可在 schema.py、policy_server.go 中继续追查;
  • 相关 OSEP 设计文档:客户端池化见 OSEP 0005 与 OSEP 0021,Credential Vault 见 OSEP 0012,出口控制见 OSEP 0001。

7. 小结

OpenSandbox Kotlin/Java SDK 以Sandbox(执行面)与SandboxManager(管理面)为双入口,配合ConnectionConfig的环境变量回退、自动重试与遥测开关,覆盖从沙箱创建、钩子、命令流式执行、文件操作到出口策略与凭证注入的完整链路;实验性SandboxPool则以 1 秒固定节奏的 reconcile、分阶段预热和AcquirePolicy策略把冷启动成本前置,且可通过sandbox-pool-redis扩展到多节点。建议在集成时优先核对timeout(默认 10 分钟)、readyTimeout(默认 30 秒)与重试策略这三组默认值是否符合你的部署环境,并保留requestId用于故障排查。

【免费下载链接】OpenSandboxSecure, Fast, and Extensible Sandbox runtime for AI agents.项目地址: https://gitcode.com/GitHub_Trending/ope/OpenSandbox

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

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

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

立即咨询