生命周期
用 Go SDK、E2B SDK 或 kibo 停止、启动和删除 Workspace。Go 示例里的 settleOptions 在 ctrl 回答仍在执行时重发命令,写法见 examples/go/quickstart。本页还介绍强制停止、怎样查看停止或删除释放了什么、FAILED 的 Workspace 怎样恢复,以及服务端在哪些情况下自己停止或重启 Workspace。
各状态下能做的操作
Workspace 能做哪些操作取决于它的状态。各状态的含义与转换见Workspace 的状态。
| 状态 | 可以做什么 |
|---|---|
CREATING | 删除,会取消正在进行的创建 |
AVAILABLE | 停止、删除、改网络策略、设置到期时间、撤销数据面访问 |
STOPPING | 删除;正常停止卡住时可以改用强制停止 |
STOPPED | 启动、删除、调整 CPU 与内存、改可写层大小、换绑 Volume、改网络策略(下次启动生效)、清除到期时间 |
STARTING | 删除 |
FAILED | 取决于是否还持有执行,见从 FAILED 恢复 |
UNKNOWN | 删除;正常停止仍在处理时可以强制停止;其余情况等系统确认结果,或用同一个幂等键重发原来的请求 |
DELETING | 等待完成 |
DELETED | 只能查询 |
- 调整 CPU、内存、可写层大小和 Volume 绑定都要求 Workspace 已停止。
- 除
DELETED外,任何状态都可以修改 labels 与 annotations,见 labels 与 annotations。 - 到期时间到了以后,系统按设置的方式停止或删除 Workspace;没有默认的到期行为,见到期时间。
停止
正常停止 Workspace:
current, err := client.Workspaces().GetWorkspace(ctx, connect.NewRequest(&ctrlv1.GetWorkspaceRequest{WorkspaceId: workspaceID}))
if err != nil {
log.Fatal(err)
}
request := &ctrlv1.StopWorkspaceRequest{
Metadata: &ctrlv1.CommandMetadata{CommandId: kibotos.NewCommandID("example")},
WorkspaceId: workspaceID,
ExpectedExpirationRevision: current.Msg.GetWorkspace().GetExpiration().GetRevision(),
}
stopped, err := kibotos.Settle(ctx, settleOptions, func(ctx context.Context) (*connect.Response[ctrlv1.StopWorkspaceResponse], error) {
return client.Workspaces().StopWorkspace(ctx, connect.NewRequest(request))
})
if err != nil {
log.Fatal(err)
}在 E2B SDK 里,停止就是暂停,见暂停与恢复。
正常停止先关闭数据面,等待 guest 中的写入完成并同步文件系统,再停止 Instance、释放资源。
- 应用程序已经交给内核的写入会被同步;仍在应用程序缓冲区中的数据需要应用自己 flush。
- 绑定的 Volume 与根文件系统的保留可写层(retained layer)都保留,内存与进程不保留。
- 为这个 Workspace 签发的数据面会话凭证全部失效,它的 Exposure 全部被撤销。下次启动后重新申请凭证、重新创建 Exposure,见公开 URL。
- 同步失败或结果未知时,正常停止不会强制销毁实例。查询这次停止的结果,停不下来时改用强制停止。
启动
启动已停止的 Workspace:
commandID := kibotos.NewCommandID("example")
started, err := client.Workspaces().StartWorkspace(ctx, connect.NewRequest(&ctrlv1.StartWorkspaceRequest{
Metadata: &ctrlv1.CommandMetadata{CommandId: commandID},
WorkspaceId: workspaceID,
ExpectedExpirationRevision: stopped.Msg.GetWorkspace().GetExpiration().GetRevision(),
}))
if err != nil {
log.Fatal(err)
}
workspace, err := client.WaitWorkspace(ctx, started.Msg.GetWorkspace(), commandID)
if err != nil {
log.Fatal(err)
}启动会创建新的实例,不恢复之前的进程和内存。
- 它接受
STOPPED的 Workspace,也接受不持有执行、没有开始过删除的FAILEDWorkspace,见从 FAILED 恢复。 - 创建在建好实例之前失败的 Workspace 也可以启动;失败的原因没有消除时,这次启动会以同样的原因失败。
- 创建还没建出 Workspace 自己的 Volume 就失败时,启动会把它建出来:Volume ID、存储池与容量都不变。
强制停止
强制停止用于正常停止完成不了的情况,包括停止卡住、FAILED 且仍持有实例:
kibo workspace stop --force "$workspace_id"它不等 guest 停止写入,只请 guest 做一次短时间同步,然后停止 Instance、释放资源。Workspace 进入 STOPPED,Volume 与可写层都保留,之后可以启动。
警告
这次同步不保证覆盖最后的写入,kibo 显示「not confirmed on disk」。下次启动时文件系统靠日志恢复一致,效果等同一次断电。
- 强制停止前
kibo会请求确认,--yes跳过确认。 - 与正常停止一样,强制停止让 Workspace 的数据面会话凭证失效,并撤销它的全部 Exposure。
- 实例的 VMM 已经退出时没有可停的机器,强制停止直接释放实例仍占用的 Volume、网络与可写层挂载,同样进入
STOPPED。 - 正常停止与到期停止失败时,服务端不会自行改为强制停止。
没有其他命令在处理时,强制停止只接受下面这些 Workspace,其余被拒绝,Workspace 不变:
| Workspace | 强制停止 |
|---|---|
AVAILABLE | 接受 |
STOPPING 或 UNKNOWN,正常停止仍在处理 | 接受。强制停止取代正常停止,原命令以 CANCELLED 失败结束 |
FAILED,仍持有执行 | 接受,不论失败发生在哪个阶段 |
FAILED,不持有执行 | 拒绝。直接启动 |
| 开始过删除(曾有删除被接受) | 拒绝。再次删除完成它;这样的 Workspace 也不接受启动与配置修改 |
删除
删除 Workspace,并等到它变为 DELETED:
commandID := kibotos.NewCommandID("example")
request := &ctrlv1.DeleteWorkspaceRequest{
Metadata: &ctrlv1.CommandMetadata{CommandId: commandID},
WorkspaceId: workspaceID,
ExpectedExpirationRevision: workspace.GetExpiration().GetRevision(),
}
if _, err := kibotos.Settle(ctx, settleOptions, func(ctx context.Context) (*connect.Response[ctrlv1.DeleteWorkspaceResponse], error) {
return client.Workspaces().DeleteWorkspace(ctx, connect.NewRequest(request))
}); err != nil {
log.Fatal(err)
}
if err := client.WaitWorkspaceDeleted(ctx, workspaceID, commandID); err != nil {
log.Fatal(err)
}delete 在请求确认前会先说明绑定的 Volume 是一起删除还是保留。--yes 跳过确认,没有终端可以提示时必须加。与 stop 一样,delete 默认最多等一小时,结束等待不会取消删除,见等待结果。
删除哪些数据
| 数据 | 删除 Workspace 时 |
|---|---|
随 Workspace 新建的 Volume(默认情况,挂在 /data) | 删除 |
用 --volume 绑定的已有 Volume | 默认保留,只解除绑定,数据原样保留 |
| 可写层(根文件系统的其余部分) | 删除 |
| 已经为这个 Workspace 签发的凭证 | 全部失效,已打开的连接被关闭 |
警告
默认情况下,删除 Workspace 会连同它的 Volume 与 /data 里的数据一起删除。要保留 Volume,在 Workspace 停止时修改绑定,或者先导出数据,见创建时的 Volume与导出、导入与恢复。
Volume 是否随 Workspace 删除是绑定的设置,不是 Volume 的种类。创建 Workspace 或绑定 Volume 时用 --delete-with-workspace 设置,见绑定、换绑与解绑 Volume。
什么时候可以删除
- 除
DELETING与DELETED外,任何状态都可以直接删除。 - 删除
CREATING的 Workspace 会取消正在进行的创建。 - 删除一旦被接受,Workspace 就不再接受启动、强制停止与配置修改。已经开始的删除要完成时,再次删除;Workspace 处于
DELETING时等它完成。 - 到期动作为
delete的到期时间到了以后,Workspace 会被删除,见到期时间。
删除之后
DELETED 的 Workspace 仍能用 kibo workspace get 按 ID 查询。列表默认不包含已删除的 Workspace,加 --include-deleted 才显示,见列表过滤。
要逐项确认运行环境、Volume、可写层等部分是否已经释放,见查看释放情况。
查看释放情况
kibo workspace cleanup-status 查看一个 Workspace 的执行已经释放了哪些部分、还占用着哪些部分。停止或删除之后,用它确认资源是否真的已经释放:
kibo workspace cleanup-status "$workspace_id"这条命令只读,不触发释放,也不改变状态。
输出包含三部分:
| 部分 | 内容 |
|---|---|
| 总体状态 | COMPLETE、PROCESSING、NEEDS_ATTENTION 或 UNKNOWN |
| Components | 逐项列出执行的各个部分,每项显示状态(RELEASED、PRESENT、PENDING、ISOLATED、UNKNOWN)、读取来源与观测时间 |
| Release | 只在释放尚未完成时出现,写明这次释放从什么时候起尚未完成,以及最后一次确认执行的时间 |
怎样看结果
- Release 一栏里的时间是诊断信息,不是期限:释放仍在重试,Components 一栏说明还占用着哪些部分。
- 观测本身不完整时,结果的
completeness为PARTIAL或UNKNOWN,退出码相应是17或18。此时未知的部分不能当作已释放。 RETAINED_LAYER或VOLUME_DELETION为PENDING、来源是控制面状态时,Workspace 已删除,文件等存储池有可用的 node 后删除。总体状态在这期间是PROCESSING。- 存储池被宣告丢失后,这两项是
RELEASED:池里已经没有可以读到的数据。
从 FAILED 恢复
「持有执行」指 Workspace 在某个 node 上还有没释放的 Instance 与资源预留。响应里没有字段直接给出它,所以恢复时不必先判断,按下面的顺序做:
- 强制停止。成功时 Workspace 进入
STOPPED。 - 启动。第 1 步被拒绝时同样执行这一步:Workspace 本来就不持有执行。
- 两步都被拒绝时,重新读取 Workspace,按它当前的状态处理。
常见的 FAILED 与是否持有执行:
| 情形 | 持有执行 |
|---|---|
| 创建或启动失败,ctrl 已经销毁下发过的实例 | 否,直接启动 |
| 创建或启动失败,销毁实例也失败 | 是 |
| 运行中 VMM 意外退出:被杀、宿主内存不足,或者 guest 内核崩溃、guest 内重启使 VMM 退出 | 是。node 保留这个 Instance,它仍占着 Volume、网络与可写层;强制停止之前启动会被拒绝 |
guest 卡住而 VMM 仍在运行时,Workspace 保持 AVAILABLE,不进入 FAILED,见 guest 回应情况。
服务端自行处理的停止与重启
宿主内存耗尽由服务端处理,不需要人工介入;guest 自己重启与关机是否也由服务端处理取决于后端:
| 情形 | Firecracker 后端 | KiboVM 后端 |
|---|---|---|
| guest 自己重启 | 保持 AVAILABLE,在同一台 node 上换一个 VMM。等 guest 回来,重试数据面请求 | 不处理。Workspace 进入 FAILED:复位与 VMM 内部故障的退出码相同,node 一律按故障处理。按从 FAILED 恢复处理 |
| guest 自己关机 | 不处理。VMM 继续运行,Workspace 保持 AVAILABLE,guest 不再回应。先强制停止再启动 | 服务端强制停止,进入 STOPPED。直接启动 |
| 宿主内存耗尽 | 服务端强制停止,进入 STOPPED。直接启动 | 与 Firecracker 相同 |
- guest 关机后与宿主内存耗尽时的强制停止,是服务端唯一会自己发起的强制停止,效果与调用方的强制停止相同:Volume 与可写层保留,最后的写入可能没有落盘。
- Workspace 已经开始删除,或者有其他命令正在处理时,服务端不发起停止。
- 要停止或重启 Workspace,用停止与启动操作,不要在 guest 里关机或重启。
guest 自己重启
在 Firecracker 后端上,guest 里执行 reboot -f、echo b > /proc/sysrq-trigger 这类复位时,node 在同一台 node 上为同一个 Instance 启动新的 VMM。Workspace 始终是 AVAILABLE,执行代与数据面凭证不变。
- Volume 与可写层保留,内存和进程不保留;没有落盘的写入可能丢失。
- guest 回来之前,数据面新请求返回可重试的
unavailable,已建立的流随旧 VMM 结束。 kibo workspace get的 Guest 一行显示重启次数与最近一次复位的时间。- 10 分钟内复位超过 3 次时不再重启,Workspace 进入
FAILED,失败信息写明复位次数,按从 FAILED 恢复处理。 - 新 VMM 没有启动成功,或重启进行到一半时 node 自身重启,Workspace 也进入
FAILED,失败信息写明原因。
guest 自己关机
在 KiboVM 后端上,guest 里执行 poweroff -f 或以 POWER_OFF 调用 reboot(2) 时,服务端对它执行强制停止,Workspace 进入 STOPPED。启动它即可继续使用。
- 停止完成之前 Workspace 仍是
AVAILABLE,这段时间数据面请求被拒绝。 - 到期策略按停止的规则处理。
- Workspace 已经开始删除或有其他命令正在处理时,服务端等下一次上报再判断。
宿主内存耗尽
宿主内存耗尽时,内核会杀掉宿主上的一台 VM。服务端对这台 VM 的 Workspace 执行强制停止,Workspace 进入 STOPPED。启动它即可继续使用。
在服务端完成停止之前,Workspace 会短暂处于 FAILED,失败信息写明宿主内存不足。
用 API
kibo 命令 | API |
|---|---|
kibo workspace stop | StopWorkspace |
kibo workspace stop --force | StopWorkspace,mode 为 STOP_MODE_FORCE。需要服务端声明能力 workspace.stop.force |
kibo workspace start | StartWorkspace |
kibo workspace delete | DeleteWorkspace |
kibo workspace cleanup-status | WorkspaceObservationService/GetWorkspaceCleanup |
- 停止的结果用命令 ID 经
GetWorkspaceCommand查询,包括正常停止同步失败或结果未知的情况。 - 强制停止被拒绝时返回
failed_precondition,ErrorDetail.reason为CONFLICT。 - 由 VMM 意外退出导致的
FAILED不设置failure.stage,因为失败不发生在任何操作里。
停止后的落盘情况
停止完成后,命令结果的 durability 说明写入是否确认落盘:
| 值 | 含义 |
|---|---|
STOP_DURABILITY_CONFIRMED | 正常停止成功,写入已同步 |
STOP_DURABILITY_UNCONFIRMED | 强制停止,包括服务端发起的;或 KiboVM 后端有一块可写盘没有刷到存储设备,这时 Workspace 照常停止 |
停止原因
Workspace 在 STOPPING 与 STOPPED 时带 last_stop,说明是哪一次停止把它带到这里;StartWorkspace 与 DeleteWorkspace 被接受后不再返回它。
| 字段 | 含义 |
|---|---|
cause | STOP_CAUSE_REQUESTED:调用方的 StopWorkspace;STOP_CAUSE_EXPIRED:到期;STOP_CAUSE_GUEST_SHUTDOWN:guest 关机;STOP_CAUSE_HOST_MEMORY_EXHAUSTED:宿主内存耗尽 |
command_id | 这次停止的命令,可以用 GetWorkspaceCommand 查结果 |
durability | 停止完成后与命令结果相同;停止完成之前为 STOP_DURABILITY_UNSPECIFIED |
服务端发起的停止,命令 ID 带固定前缀:
- guest 关机为
guest-shutdown/。 - 宿主内存耗尽为
host-memory/。
调用方的命令 ID 不能使用这两个前缀,否则返回 invalid_argument。guest 关机后进入 STOPPED 的行为对应能力 workspace.stop.guest_shutdown。
排查
启动被拒绝
- 现象:
FAILED的 Workspace 启动返回错误。 - 原因:Workspace 仍持有执行,旧实例还可能占着存储。
- 处理:先强制停止再启动,见从 FAILED 恢复。
下一步
- Volume 与导出恢复:删除 Workspace 时保留 Volume,或先导出数据。
- 到期时间:让 Workspace 到时自动停止或删除。
- 资源与运行状况:调整已停止 Workspace 的资源,查看 guest 是否回应。
- kibo 命令行:
kibo怎样等待停止、启动与删除完成。