资源与运行状况
本页介绍如何调整 Workspace 的 CPU、内存与磁盘,guest 里有哪些任务数与内存限制,怎样判断 guest 是否还在回应、是否卡在内存上,以及如何读取一段时间的资源读数。
调整资源
kibo workspace update 修改 Workspace给 AI Agent 用的完整 Linux 环境,运行在独立的 MicroVM 里。Agent 在里面读写文件、运行进程、启动服务,不会影响宿主机和其他 Workspace。 请求的资源,--cpu、--memory、--disk 至少给一项。取值写法与 create 相同,都是最终值而不是增量。
先停止 Workspace,修改资源后再启动:
kibo workspace stop "$workspace_id"
kibo workspace update "$workspace_id" --cpu 2 --memory 4G --disk 40G
kibo workspace start "$workspace_id"--cpu与--memory只更新配置,下次启动时生效。命令成功表示新值已保存,不代表下次启动一定能分到足够的 node 容量。因容量不足启动失败后,可以用这条命令调小再试。--disk立即扩大可写层,内容保留。可写层所在的存储容不下新的大小时,命令以resource_exhausted失败,容量不变。
网络策略用 kibo workspace network 修改,见网络策略。
可以修改的情形
Workspace 必须不持有执行。下表列出各种情形下要先做什么:
| Workspace | 执行 update 之前 |
|---|---|
STOPPED | 不需要 |
FAILED、已经不持有执行、也没有开始过删除,不论失败发生在哪个阶段 | 不需要 |
| 运行中 | 先执行 kibo workspace stop,否则 update 退出码为 13 |
FAILED、仍持有执行 | 先执行 kibo workspace stop --force,见强制停止 |
| 开始过删除 | 资源不能再改,只能再次执行 kibo workspace delete |
CPU 与磁盘的取值
- 实例拿到的 vCPU 数是毫核按千向上取整:
1.5得到 2 个 vCPU,0.5得到 1 个。单个实例能给多少 vCPU 由承载它的 node 在启动时判定。 --disk设置可写层Workspace 根文件系统的可写部分,保存安装的软件包这类修改;Operator 的页面称它为保留的可写层。可写层尽力保留,只有 Volume 保证保留数据。的容量,只能增大,已有内容全部保留。等于当前容量时什么都不做;小于当前容量时返回invalid_argument。- 从未启动过的 Workspace 只记录这个容量,第一次启动时按它创建可写层。
kibo workspace get的 Disk 一行在可写层尚未创建时写明created at first start,请求值与实际容量不同时两者都显示。
部分生效
服务端的内存、CPU 与可写层是三条独立的命令,没有一次修改多项的原子操作。update 只提交给出的项,顺序为内存、CPU、磁盘:
| 情形 | 结果 |
|---|---|
| 全部成功 | 输出最终的 Workspace 与各项结果,退出 0 |
| 第一项就失败 | 什么都没改,按失败原因退出,例如运行中返回 13 |
| 前面的项已生效后某项失败 | 逐项列出 applied、failed、not submitted,不再提交后面的项,退出 17 |
| 某项结果未知 | 退出 18,给出该项的幂等键 |
版本与重放
CPU 与内存按同一个资源版本校验,磁盘不校验版本。规则如下:
- 不传
--expected-revision时,kibo先读取当前版本再提交。提交时版本已变化,update返回冲突,不自动重试。 - 设置为相同的值不会改变版本。
- 脚本需要重放时,把
--command-id与--expected-revision一起传入。各项的幂等键是它加上/memory、/cpu、/disk。
每一项对应的 API 方法见修改资源。
guest 里的限制
guest在 Workspace 的 MicroVM 里运行的 Linux 系统。其中的 guest agent 代 node 执行文件与进程操作。 为内核与平台进程留出一部分任务数和内存。用户进程用满自己的份额时,文件操作、进程管理与停止照常可用。
任务数
每个进程、每个线程各算一个任务。有两层限制:
| 范围 | 上限 | 用满之后 |
|---|---|---|
| Workspace 里的全部进程 | 比内核上限少 256 + 32 × CPU 数,这部分留给内核线程与 guest 程序 | 所有进程里新的进程与线程创建失败(EAGAIN),ProcessService/Start 返回 resource_exhausted,可以重试 |
每个 ProcessService/Start 启动的进程连同它的后代,以及桌面 | 最多为上面总数的 3/4 | 其中新的进程与线程创建失败(EAGAIN)。一个进程失控时停在这里,其他进程照常启动 |
内存
- Workspace 里全部进程合计能用的内存比 guest 启动时的可用内存少一部分。少的这部分是内存的 1/16,在 64 MiB 与 256 MiB 之间,留给 guest 程序与内核。
- 合计用满后,内核结束其中占用内存最多的进程,其他进程照常运行。
- 进程持续卡在等内存上时,guest 也会结束其中最大的进程,见内存饱和。
系统文件
guest 每次启动重写 /etc/hostname、/etc/hosts 与 /etc/resolv.conf。在 guest 中对它们的修改,包括加上的 immutable 或 append-only 属性,都不跨启动保留。
guest 回应情况
运行中的 Workspace 带一份 guest 观测。运行它的 node 定期探测 guest,连续几次超时或连不上就判为不再回应,回应一次就解除。
列出 guest 已不再回应其 node 的 Workspace,再查看其中一个:
kibo workspace list --guest-unresponsive
kibo workspace get "$workspace_id"list输出末尾的 GUEST NOT RESPONDING 一节给出每个 guest 不再回应的起始时间与最近一次错误。get的 Guest 一行显示同一份观测。guest 自己复位过时,还带重启次数与最近一次复位的时间。
观测的含义
- 它是观测,不是状态。 guest 不再回应时 Workspace 仍是
AVAILABLE,准入与到期回收都不看它,guest 也可能自己恢复。数据面请求在这期间照常超时。node 重启时 guest 恰好不回应也一样。 - 什么时候没有。 没有运行中实例的 Workspace(例如
STOPPED)不带它;node 尚未上报、guest 正在自己重启时也不带。 - guest 自己重启之后。 guest 重新回应后,观测会表明 guest 重启过。重启次数,即这次执行里 guest 自己复位、node 换了 VMM 的次数,加 1;最近一次复位的时间就是这一次的时间。下一次执行从 0 开始计数。
- 多久能看到。 从 guest 卡住到能查到,一般在 2 分钟以内。
恢复不回应的 guest
guest 可能自己恢复。一直不恢复的 guest 用强制停止收回,再启动:
警告
强制停止不等 guest 停止写入,guest 尚未刷写的数据可能丢失。见强制停止。
kibo workspace stop --force "$workspace_id"
kibo workspace start "$workspace_id"内存饱和
guest 回应正常,不代表里面的进程在干活。guest 没有 swap,进程合计用到内存上限时,内核总能从这些进程自己的文件页(代码、读入的文件)里回收出一点,于是反复回收、再读回,不会触发 OOM。进程几乎停滞,可以持续数小时,而 guest 照常回应探测。
guest 观测用内存状态报告这种情况,kibo workspace get 的 Guest memory 一行显示它:
| 显示 | 含义 |
|---|---|
normal | guest 在统计内存压力,进程没有顶在上限 |
saturated at the memory limit since … | 在最近一段持续的时间里,进程大部分时间全部卡在等内存上 |
unknown | 未知,不等于正常。Workspace 用的 Platform 或 node 不支持这项上报,或 guest 不再回应 |
判定与处置随 Platform 交付,Workspace 用上带这项上报的 Platform 后才有;之前内存状态为 unknown,guest 也不结束进程。Firecracker 的 guest 内核要以 psi=1 启动才统计内存压力,本版本的 Firecracker Platform 已经带上。
饱和的判定
- 判定依据。 guest 按最近 60 秒里全部进程同时卡在等内存上的时间占比判断:达到 25% 判为饱和,降到 10% 以下解除。
- 不算饱和的情况。 短时的内存高峰占不满窗口,不会判为饱和。内存占满但进程不卡在等内存上,比如空闲的 Workspace,占比接近 0。
- 它同样是观测。 饱和不改变 Workspace 的状态、准入与到期回收。需求降下来后会自己解除;一直不解除时,guest 按下一节的规则结束进程。
- 多久能看到。 从进程开始停滞到能查到,一般在 2 分钟以内;解除也要等窗口里的停滞占比降下来。
饱和时结束进程
饱和持续下去时,guest 向其中占用内存最多的进程发 SIGKILL,让其余进程继续运行。
- 什么时候结束。 同时满足三条:
- 饱和已持续 90 秒。
- 当前 60 秒窗口的占比仍不低于 25%。占比已回落到 25% 以下的不处置,它在继续报饱和但已经能往前走。
- 这段时间里进程确实撞到过内存上限。没撞到上限的停滞是整个 guest 缺内存,交给内核的 OOM killer。
- 结束谁。 受管进程里常驻内存(RSS)最大的一个。guest agent 与平台进程不在其中,不会被选中。只结束这一个进程,它的子进程和同一会话的其他进程不受影响,除非它们随它退出。
- 之后。 60 秒冷却期内不再处置。冷却期结束仍符合上面三条的,按同样的规则结束下一个。
- 怎样区分。 被结束的进程按被信号 9 杀死退出,和内核 OOM 杀进程看起来一样。
kibo workspace get多出的 Guest memory kills 一行显示次数、最近一次结束的进程与原因;guest 日志与 node 日志各有一条记录。 - 次数保留多久。 结束进程的次数与最近一次结束的进程随 guest 重启清零,guest 不再回应时仍保留,Workspace 停止后消失。
结束进程解决不了的情况
- tmpfs(
/tmp、/run、/dev/shm)里的内存不属于任何进程,结束进程释放不了。 - 占比一直低于 25% 的抖动不会判为饱和,也就不会被处置。
读取资源读数
kibo workspace metrics 显示一个 Workspace 一段时间的资源读数,默认最近 1 小时。部署要为读取接好实例指标存储,否则 kibo 在读取之前就停下;它检查的能力见资源读数。
读取最近 24 小时,或以 JSON 输出一段固定区间:
kibo workspace metrics ws-0123 --since 24h
kibo workspace metrics ws-0123 --start 2026-11-06T08:00:00Z --end 2026-11-06T09:00:00Z --json宿主侧与 guest 内的读数
读数分两条序列,都按同一个步长分桶:
| 序列 | 从哪里读 | 字段 | guest 能否改动 |
|---|---|---|---|
host | 宿主上,guest 之外 | cpu_cores、memory_bytes、五个压力占比,以及两个方向每秒的网络字节、包数与丢包数 | 不能。guest 不应答时照常有点 |
guest | guest 里 | 与 E2B sandbox 指标相同的七个值:CPU 数与使用率,内存总量、已用与缓存,磁盘总量与已用 | 能,guest 里的 root 可以改。guest 不应答时没有点 |
分桶
ctrl 按区间长度 end − start 选步长:
| 区间 | 步长 |
|---|---|
| 不到 1 小时 | 5 秒 |
| 不到 6 小时 | 30 秒 |
| 不到 12 小时 | 1 分钟 |
| 不到 24 小时 | 2 分钟 |
| 不到 7 天 | 5 分钟 |
| 更长 | 15 分钟 |
- 速率(
cpu_cores、压力占比、网络字段)是桶内平均值:速率乘步长就是这个桶内的总量。瞬时值(memory_bytes与 guest 的全部字段)是桶内最大值。 - Workspace 的每次执行合并成一条序列,停止后在另一台 node 启动也一样。两次执行之间不补点。
- 宿主侧的点只带存储里有样本的字段。guest 内的点七个值齐全才返回。
- 需要超过 4000 个桶的区间以
invalid_argument被拒绝,用--start与--end缩小。
保留期与缺口
- 能读多久取决于存储的保留期。不要假设固定长度,需要更长的历史就自己转存。
- 读数是观察数据,不是用量记录。存储不可达、guest 不应答或 node 重启时会有缺口。
- 已删除的 Workspace 在存储还保留读数期间照常可读。没有读数的 Workspace 返回两条空序列。
用 API
本节列出上面各条 kibo 命令背后的方法、字段与能力。
修改资源
kibo workspace update 对应三个方法:UpdateWorkspaceMemory、UpdateWorkspaceCpu 与 ResizeWorkspaceWritableLayer。调整资源里的规则对每个方法都适用。
- 内存与 CPU 使用乐观锁,两者共用一个资源版本
resources_revision。 - 可写层扩容没有期望版本,只有幂等键和目标容量。
guest 观测
Workspace 的 guest_observation 就是 guest 回应情况与内存饱和里的那份观测,能力名为 workspace.guest_observation。全部字段见 GuestObservation。
condition为GUEST_CONDITION_RESPONDING或GUEST_CONDITION_UNRESPONSIVE。rebooted、restart_count与last_reset_at描述 guest 自己的重启。memory_condition为GUEST_MEMORY_CONDITION_NORMAL、GUEST_MEMORY_CONDITION_SATURATED或GUEST_MEMORY_CONDITION_UNSPECIFIED,kibo分别显示为normal、saturated at the memory limit since …与unknown。memory_kill_count与latest_memory_kill描述 guest 在饱和时结束的进程。
ListWorkspaces 的 guest_condition 只返回当前观测为该值的 Workspace:
- 可以与
states、label_selector组合。 - 翻页时它必须与取得游标的那次请求相同。
- 老版本的服务端会忽略
guest_condition、返回全部 Workspace。筛选前先确认能力workspace.guest_observation存在。
资源读数
kibo workspace metrics 对应 WorkspaceMetricsService/GetWorkspaceMetrics。部署要为读取接好实例指标存储,并宣告 workspace.metrics.get;kibo 在调用方法之前检查这项能力。请求与响应见 WorkspaceMetricsService。
- 响应带所用的步长,以及存储里还能读到的最早时刻
earliest_time。 - 存储没有及时应答时,方法返回
unavailable。 - 同时进行的读取太多时,立即返回
resource_exhausted,其他方法不受影响。 - ctrl 从来没有过的 ID 返回
not_found。
排查
数据面请求一直超时
- 现象:Workspace 是
AVAILABLE,执行命令、读写文件都超时。 - 原因:guest 不再回应。用
kibo workspace list --guest-unresponsive或kibo workspace get确认。 - 处理:guest 可能自己恢复;一直不恢复时强制停止再启动。
进程几乎停滞
- 现象:guest 照常回应,命令能执行,但应用进程长时间几乎没有进展,或者被信号 9 结束。
- 原因:进程合计用到了内存上限。
kibo workspace get的 Guest memory 一行为saturated…,或出现 Guest memory kills。 - 处理:减少负载,或停止后调大内存。tmpfs 占满内存时清理
/tmp、/run、/dev/shm里的文件;命令也执行不动时,强制停止再启动。