Kibotos

资源与运行状况

本页介绍如何调整 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 一行显示它:

显示含义
normalguest 在统计内存压力,进程没有顶在上限
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 不应答时照常有点
guestguest 里与 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 里的文件;命令也执行不动时,强制停止再启动。

下一步

本页内容