Sandbox 与生命周期
用 E2B SDK 在 Kibotos 上创建、暂停、恢复、延期和删除 sandbox,调用与 E2B 相同。本页介绍各个生命周期调用在 Kibotos 上的行为、新 sandbox 得到的资源、到期时间与 Idempotency-Key 重试的规则,以及查询返回的内容。
概述
每个 sandbox 在 Kibotos 里是一个 Workspace给 AI Agent 用的完整 Linux 环境,运行在独立的 MicroVM 里。Agent 在里面读写文件、运行进程、启动服务,不会影响宿主机和其他 Workspace。。生命周期调用对应下面这些接口:
| SDK 调用 | 接口 | 在 Kibotos 上 |
|---|---|---|
Sandbox.create | POST /sandboxes | 按部署设定的资源创建 sandbox,见创建 sandbox |
getInfo() | GET /sandboxes/{id} | 返回实际生效的配置,见 sandbox 信息 |
| SDK 的列表调用 | GET /v2/sandboxes | 列出 sandbox,包括暂停中的 |
sandbox.kill() | DELETE /sandboxes/{id} | 删除 sandbox。用 volumeMounts 挂载的独立 Volume 保留;创建时没带 volumeMounts 的 sandbox,它的 /data Volume 随之删除。见 Volume |
sandbox.pause() | POST /sandboxes/{id}/pause | 冷暂停,见暂停与恢复 |
Sandbox.connect | POST /sandboxes/{id}/connect | 恢复暂停中的 sandbox,有效期只延长不缩短 |
sandbox.setTimeout | POST /sandboxes/{id}/timeout | 设置到期时间,可延长也可缩短,见到期时间 |
| 无 | POST /sandboxes/{id}/refreshes | 延长有效期,至少 15 秒 |
本页的示例省略了连接选项(apiKey、domain、apiUrl),写法见 E2B 兼容里的示例。
创建 sandbox
创建一个有效期十分钟、到期时暂停而不是删除的 sandbox:
import { Sandbox } from 'e2b';
const sandbox = await Sandbox.create('kibotos-minimal', {
timeoutMs: 10 * 60_000,
lifecycle: { onTimeout: 'pause', autoResume: false },
});- sandbox 运行起来后请求返回 201,最长等待 90 秒。到时仍未运行的返回 502,这个 sandbox 之后仍可能启动。用同一个
Idempotency-Key重试,等待的是这个 sandbox,不会再创建一个,见用 Idempotency-Key 重试。 - 请求体超过 1 MiB 时返回 400。
- 资源取自部署配置,而不是请求,见资源。
- 没有 node 能放置时,创建返回 503,见容量不足。
- sandbox 的有效期见到期时间。
metadata 与选项的大小
网关把 metadata 与 E2B 选项存进 ctrl,因此受 ctrl 的合计上限约束:
| 上限 | 值 | 计入 |
|---|---|---|
| annotations 合计 | 262144 字节 | metadata 的 JSON 原文,加上 maskRequestHost 等其他 annotation 的 key 与 value |
| labels 合计 | 65536 字节 | 每个 metadata 条目的 label(key 超过 63 字符或不合 label 规则时按 48 字符摘要计),加上命名空间、token、布尔选项等其他 label 的 key 与 value |
超出任一上限时,创建返回 400,不创建 sandbox。
资源
E2B 的创建请求不带资源字段,网关按部署参数为每个新 sandbox 申请资源:
| 资源 | 网关配置 | 默认值 |
|---|---|---|
| CPU | KIBOTOS_E2B_DEFAULT_CPU_MILLIS | 1 核 |
| 内存 | KIBOTOS_E2B_DEFAULT_MEMORY_BYTES | 1 GiB |
| 根文件系统的可写空间 | KIBOTOS_E2B_DEFAULT_DISK_BYTES | 5 GiB |
cpuCount、memoryMB、diskSizeMB回显 sandbox 实际得到的值。diskSizeMB是 node 确认过的可写空间。sandbox 正在启动、或从未成功放置时还没有确认的值,GET /sandboxes/{id}与列表接口照常返回它,diskSizeMB为0。E2B 要求这个字段是非负整数、不能为空,上游缺少这个值时同样返回0。- 可写空间从放置起占用 node 存储池的容量,实际写入的数据才占用磁盘。存储池小的部署要按 sandbox 数量调小这个值。
- 配置只影响之后创建的 sandbox,已有 sandbox 的可写空间不变。
部署方按安装 E2B 网关设置这些变量。
暂停与恢复
暂停一个 sandbox,再恢复它:
await sandbox.pause();
const resumed = await Sandbox.connect(sandbox.sandboxId);在 Kibotos 上,暂停是「冷暂停」:网关调用 Kibotos 的 StopWorkspace 停止 sandbox,恢复时调用 StartWorkspace 重新启动。这是 Kibotos 明确选择的语义。
暂停后保留 sandbox ID 和 Volume(默认挂在 /data)。恢复时重新启动一个新的执行,envd token 与 traffic token 不变。
警告
内存和运行中的进程不保留。根文件系统的修改只是尽力保留,不能当作完整的磁盘快照。需要保留的文件写入 Volume。
暂停
POST /sandboxes/{id}/pause 执行冷暂停:
- 空请求体、
memory:true、memory:false都执行冷暂停。SDK 的pause()默认发送memory:true,网关同样按冷暂停处理,不声称支持内存暂停。 - 确认 sandbox 已停止后返回 204。
- 重复暂停返回 409,SDK 把它转换为返回
false。 - 暂停会清除到期时间,见到期时间什么时候变化。
恢复
POST /sandboxes/{id}/connect 的结果取决于 sandbox 的状态:
| sandbox 状态 | 结果 |
|---|---|
| 运行中,或仍在启动 | 运行起来后返回 200。到期时间只延长不缩短,见到期时间 |
| 已暂停,或上次因可重试的原因失败 | 启动它并设置本次的有效期,等待启动完成后返回 201 |
| 已暂停,且没有 node 能放置 | 503,消息含 resource_exhausted。sandbox 仍是暂停,见容量不足 |
| 90 秒内没有运行起来 | 502。启动之后仍可能完成,用同一个 Idempotency-Key 重试 |
| 因不可重试的原因失败,或在等待期间失败 | 409,消息以 sandbox failed: 开头 |
| 已失败且仍占着上次的执行,包括放置失败后 Kibotos 没能释放 node 的少数情况 | 409,Kibotos 拒绝再次启动。运维用 kibo workspace stop --force 停止它之后,connect 即可恢复 |
返回的 token 与创建时相同。与 E2B 一致,connect 不轮换 token。
意外的暂停、重启与失败
| 情形 | sandbox 状态 | 怎样处理 |
|---|---|---|
| 宿主内存耗尽,sandbox 被内核杀掉 | 暂停 | connect 即可恢复。与主动暂停一样,内存和进程不保留,最后的写入可能丢失 |
| guest 自己关机 | 暂停 | connect 即可恢复 |
| guest 自己重启 | 仍是 running,查询与 connect 照常成功 | envd 与应用端口的请求在 guest 回来之前失败,重试即可。内存和进程不保留 |
| 其他原因意外结束,例如 VMM 故障 | 失败,不会自行恢复 | connect 返回 409,查询与暂停返回 502,列表不列出它,重试都不会成功。运维用 kibo workspace stop --force 停止它之后,connect 即可恢复 |
Kibotos 怎样处理这些情形、适用哪些后端,见服务端自行处理的停止与重启。
容量不足
启动时没有 node 能放置 sandbox(例如所有 node 内存都紧张),这次 connect 返回 503,消息含 resource_exhausted。其他接口遇到容量不足(例如创建 sandbox 或 Volume)同样返回 503。
- 这样的 sandbox 与上游 E2B 恢复失败时一样仍是暂停:查询返回
state: paused,列表按暂停列出,再次暂停返回 409。容量恢复后再次connect即可启动它,不需要运维介入。 - 创建时就没能放置的 sandbox 也按暂停列出。用 metadata 找到它,再
connect启动或删除。 - 启动失败后的到期时间见启动失败之后。
通过应用端口自动唤醒(autoResume)、快照与克隆目前不可用,见不支持的能力。
到期时间
让运行中的 sandbox 在十分钟后到期:
await sandbox.setTimeout(10 * 60_000);各请求设置到期时间的方式不同:
| 请求 | 效果 |
|---|---|
create | 按请求的 timeout 设置有效期。JS SDK 总会发送 timeout,不设 timeoutMs 时是 5 分钟;请求不带 timeout 时用网关的 KIBOTOS_E2B_DEFAULT_TIMEOUT,默认 1 小时。倒计时从 ctrl 接受命令开始,包含创建耗时 |
connect | 只延长:新的 endAt 是现有到期时间与「now + 请求的 timeout」中较晚的那个。恢复时设置本次的有效期,从 ctrl 接受启动命令时开始计算,启动耗时算在其中 |
timeout | 按请求值设置到期时间,既可延长也可缩短 |
refreshes | 只延长,至少 15 秒(E2B 的 SandboxTimeoutDefault)。duration 缺省、小于 15 秒或不是正数,都按 15 秒处理 |
到期动作
| 创建选项 | 到期时 |
|---|---|
不设置,或 lifecycle.onTimeout: 'kill' | 删除 sandbox |
autoPause: true(SDK 的 lifecycle.onTimeout: 'pause') | 暂停 sandbox,而不是删除 |
timeout与connect保持创建时设置的动作。- 没有开启
autoPause时,恢复后的 sandbox 到期仍是删除。 autoPauseMemory的两个取值都按冷暂停处理。只设置autoPauseMemory而没有开启autoPause返回 400。
timeout 的取值
timeout的取值与 E2B 相同:正整数是秒数;0与负数都表示立即到期。E2B 用endAt = now表达,网关用最短的正期限表达,因为 ctrl 只接受正的到期时长。connect与timeout的请求字段在 E2B 里是必填,缺失时按0处理。只有create可以省略。- 对
connect来说,0、负数与缺失字段请求的都是「现在」,因此保持原值。请求的 timeout 比剩余时间短时保持原值,不推进原生的到期 revision。这与 E2B 相同,connect只增不减。 - 部署可以用
KIBOTOS_E2B_MAX_TIMEOUT限制单次请求的时长。create与connect超过上限时返回 400,与 E2B 在团队上限处的位置相同;timeout与refreshes不做这个检查,E2B 也不做。
到期时间什么时候变化
- 这些请求都在原生的到期设置更新成功后才返回成功。
inspect与list返回的endAt直接来自原生的到期时间。 - 访问文件与执行命令不会改变有效期。
- 暂停或恢复时,到期时间和状态变化在同一次原生调用中提交。暂停成功的 sandbox 没有到期时间,之前设置的删除动作不会在暂停期间触发;启动成功的 sandbox 一定带有本次的到期时间。启动失败是例外,见启动失败之后。
- 到期动作由 ctrl 执行,网关没有自己的定时器。网关停止不影响已设置的到期时间。
- ctrl 暂时不可用时延期会失败,恢复后 ctrl 按已保存的时间执行到期动作。
- ctrl 已开始执行到期动作后,不能再通过延期取消。
启动失败之后
- 恢复前没有到期时间的 sandbox(例如暂停中的),恢复失败后仍没有到期时间,超过这次请求的
timeout也不会被暂停或删除。 - 启动命令在 ctrl 接受时就写入了本次的到期时间,网关在启动失败后再发一次原生调用清除它。网关在这两次调用之间退出时,这个到期时间会保留。
- 创建时就没能放置的 sandbox 保留创建时的到期时间,到期后按创建时的设置删除;对它的
connect失败时,到期时间换成这次请求设置的。
用 Idempotency-Key 重试
create、connect、pause、timeout、refreshes、修改网络和删除支持 Idempotency-Key 头。同一个 key 的请求内容必须相同。key 超过 256 字节时返回 400。
结果未知时(例如请求中断后),用同一个 key 重试。网关先向 ctrl 查这条命令是否已经提交:已提交就等它完成并返回结果,未提交才重新发起。
Idempotency-Key的值不是 Kibotos 的幂等键(command ID)调用方为每个写请求生成的稳定标识。用同一个幂等键重发请求,操作不会执行两次。。网关把它与命名空间、操作和 sandbox 一起推导出幂等键,同一个值用在不同操作上会得到不同的幂等键,不能拿它去原生 API 查询命令。- 幂等键由 key 推导,网关不保存任何东西。以上都不依赖网关本地状态,换一台网关实例重试同样成立。
- 同一个 key 换了请求内容,ctrl 判为冲突,网关返回 409。
- 删除与
refreshes同样按 key 推导幂等键,重试时等待同一条命令完成。 - 版本冲突返回 409。网关不会读取新版本后重试旧请求,需要基于当前状态发起新请求。
sandbox 信息
GET /sandboxes/{id} 与列表接口返回实际生效的配置。与生命周期有关的字段:
| 字段 | 回显规则 |
|---|---|
lifecycle | 到期动作为删除时返回 {"onTimeout":"kill","autoResume":false},为暂停时返回 onTimeout:"pause"。暂停中的 sandbox 没有到期时间,回显的是下次启动将使用的设置 |
endAt | 直接来自原生的到期时间 |
cpuCount、memoryMB、diskSizeMB | sandbox 实际得到的值,见资源 |
SDK 2.46.1 的 getInfo() 保留这些字段以及网络、端口与 Volume 的字段。SDK 的列表调用只保留 volumeMounts,其他字段需要通过 getInfo() 读取。
其他字段的回显规则在各自的页面:网络字段见网络,allowPublicTraffic 与 maskRequestHost 见应用端口,volumeMounts 见 Volume。
注意
- sandbox 的实际状态与到期时间以原生 API 的查询结果为准。