node
本页介绍如何让 node 停止接收新的 Workspace、在 node 宕机或失联时将它隔离、退役 node、设置超卖倍数,以及查找和指定 Workspace 所在的 node。
- 示例直接调用
kibo。建立连接见 身份与注册。 - 全局参数、退出码与 JSON 输出见 kibo CLI 参考,写命令的幂等键与期望版本见幂等键与期望版本。
- Template 与 Platform 的构建和发布见构建自己的 Template与在构建机上构建并发布。
node
用 kibo node 查看 node 的注册状态,并在维护前让它停止接收新的 Workspace:
node_id=node-a
kibo node list --page-size 20
kibo node get "$node_id"
registration_version=$(kibo node get "$node_id" --json | jq -er '.result.registration_version')
kibo node drain "$node_id" --command-id drain-a --expected-version "$registration_version"
# 需要等待清空时可在提交 drain 时加 --wait --timeout 10m。
kibo node cancel-drain "$node_id"list 与 get
两条命令原样返回 ctrl 中的节点注册记录:
| 字段 | 内容 |
|---|---|
node_id、admission、drain_requested | 节点 ID、是否已获准加入、是否已请求 drain |
isolated | 是否处于isolate 声明生效的状态 |
| status | ctrl 推导出的当前状态 |
| 最近一次会话 | 启动序号(incarnation)、会话 ID、node 的版本、是否存活 |
| 最近一次完整上报 | 上报时间、已分配的资源、这个 node 持有的 Instance 与 Volume 数量 |
schedulable 与 overcommit | 放置实际使用的 CPU 与内存,以及生效的倍数和来源(全集群默认或本 node 覆盖),见 overcommit |
host_usage | 控制连接存活时,node 最近一次采样的实际用量;只在 get 里显示 |
registration_version | drain、cancel-drain、isolate 与 overcommit set 的期望版本 |
list 的人读输出是每个 node 一行的表格;--json 输出的 result 与 API 字段同名。list 的排序与分页由服务端完成。
| 列 | 内容 |
|---|---|
RELEASE | node 二进制的发布版本。未正式发布的构建显示 unreleased,没有值时显示 - |
CLOCK | ctrl 最近一次测得的 node 时钟偏差(node 减 ctrl)。超过允许偏差时标 (over)。控制连接不在时显示 - |
INSTANCES | node 最近一次上报的 Instance 数量 |
CPU_ALLOC/SCHED、MEM_ALLOC/SCHED | 已分配量与可调度量。CPU 以核数显示,内存按最大的二进制单位保留一位小数 |
MEM_TIGHT | 宿主内存是否紧张,见 Host usage |
REG_VERSION | 注册记录的版本,只在 --wide 中显示 |
kibo node get 与 JSON 输出分别给出发布版本、源码 revision 和注册记录版本,node get 的注册记录版本、启动序号、会话 ID 与上报版本只在 --wide 中显示;Latest session 一节还给出时钟偏差的不确定度与 node 宿主内核报告的同步状态。
控制会话开始时以及之后每次定期同步 node 状态时,ctrl 都测量一次 node 的时钟。偏差减去不确定度后超过 30 秒时,调度不再把新的 Workspace 放到这个 node 上,已有的 Workspace 继续运行。之后某次测量回到 30 秒以内,这个 node 才重新接收新的 Workspace,因此要修正宿主机的时间同步。
drain 与 cancel-drain
- 两者都以
registration_version作为期望版本。会话变化、资源上报和管理操作都会让这个版本递增。 - drain 只做一件事:ctrl 不再把新的 Workspace 调度到这个 node,node 本身也拒绝新的创建请求。已有 Workspace 的停止、删除、导出照常执行。
cancel-drain恢复调度。 - drain 不会迁移或销毁 Workspace。要清空一个 node,Operator 需要自己用
kibo workspace stop/delete或kibo transfer export处理上面的 Workspace;kibo workspace list --node "$node_id" --all -q列出它们。 kibo不会代替你操作宿主机。维护顺序是:drain → 清空 Workspace → 看到DRAINED→ 停止 node 服务。
drain --wait
提交后按固定间隔查询,直到 Instance 与 Volume 数量都归零:
| 结果 | 退出码 | 说明 |
|---|---|---|
状态到达 DRAINED | 0 | |
超过全局 --timeout 仍未到达 | 16 | drain 请求已经提交,drain_requested 保持为 true。kibo 不会再提交一次 |
| 等待期间 drain 被取消或 node 被撤销 | 13 |
DRAINED 的条件是这个 node 上不再运行任何 Instance,也不再持有任何 Volume 或保留的可写层的使用权(use right):一个共享存储池里别的 node 持有使用权的对象不计入这个数量。只要还有一项不满足,状态就停在 DRAINING。
isolate
kibo node isolate 是操作员对一个 node 的断言:"这台宿主机已经关机,或者它已经写不到自己的任何存储池"。这不是 ctrl 自己能验证的事实:
kibo node isolate "$node_id" --command-id isolate-a --expected-version "$registration_version" --confirm-host-cannot-write- 必须带
--confirm-host-cannot-write:操作员在断言这个事实,也在承担断言错了的后果——一个其实还在写存储的 node 被声明 isolate,会损坏它正在使用的块文件。 - 只要这个 node 还有存活的控制会话,isolate 就会被拒绝(退出码
13):能负责任地做这个断言的只有 ctrl 之外、正在看着这台宿主机的操作员。
成功后,ctrl 一次完成下面几件事:
- 释放这个 node 持有的每一个 Volume 与保留的可写层的使用权,共享池与只有它接入的池都算。
- 释放这个 node 名下所有的分配。
- 这个 node 上运行的每一个 Workspace 变为
FAILED,原因是UNAVAILABLE,可以重试启动。 - 发给这个 node、还没有完成的命令失败。
返回结果给出释放的 Volume 数、保留的可写层数与因此失败的 Workspace 数。
这些 Workspace 什么时候能重新启动或删除,取决于它们的对象在哪个池:
| 对象所在的池 | 能重新启动或删除的时机 |
|---|---|
| 共享池 | 不必等这个 node 回来,由另一个接入这个池的 node 启动或删除 |
| 只有这个 node 接入的池 | 这个 node 回来之后,或者另一台接入同一个池的宿主机加入之后 |
- 重新启动后的数据与宿主机掉电后相同:已经写到池里的内容都在,旧宿主机页缓存里还没回写的写入可能丢失。
- 共享池放在 NFS 上时,另一个 node 能正确接手的前提是挂载没有加
nocto,见把存储池放在 NFS 上的前提条件。 - isolate 会让这个 node 当前的启动序号(incarnation)失效:用这个或更早的启动序号重新连接会被拒绝,ctrl 同时告诉这个 node 它已被 isolate。
- node 收到后销毁自己的全部 Instance,然后退出,由 systemd 重启;重启后以新的启动序号重新连接,isolate 自动清除,不需要额外的命令。
- 共享池上的对象已经交给别的 node 时,原 node 即使没有连上 ctrl,也会在几秒内从池里的持有者记录发现这一点,自行停掉仍在写这些对象的 Instance。
- isolate 不删除任何对象,也不代替你确认宿主机确实已经关机或确实已经断开存储。声明错了没有事后校验,后果是数据损坏。
retire
宿主机不再回来时,用 kibo node retire 让这个 node 退役。退役是终态:
kibo node retire "$node_id"- 只接受状态为
DRAINED的 node,或当前启动序号已被 isolate 的 node,其余返回failed_precondition,退出码13。 - 执行前要在终端确认;没有终端时加
--yes。显式--command-id时必须同时给--expected-version,同一对重放返回同一结果。
退役之后:
- 这个 node 不再是任何存储池的成员,待使用的 enrollment grant 被撤销,控制会话被关闭。
- 它的登记保留下来,状态是
RETIRED。Allocation 和对象的上一任持有者还引用这条记录。 - 它不能再登记。给同一个
node_id签发 grant、drain、isolate 都返回failed_precondition。新宿主用新的node_id。 - 被 isolate 之后退役的 node 如果回来,以被 isolate 的启动序号连接时照样收到隔离拒绝并销毁全部 Instance;换了新的启动序号才因未准入被拒绝。
- 最近一次执行在它上面的 Workspace,
kibo workspace cleanup-status的RUNTIME、VOLUME_ATTACHMENT、RESIDUAL显示RELEASED,来源是控制面状态。
与退役的 node 一样,kibo enrollment revoke 撤销的 node 不是池成员:它不列在池的 Nodes 里,也不算作别的 node 进入 DRAINED 时「池的另一台接入 node」。
只有它接入的池退役后没有成员。这时分两种情况:
- 盘完好:把盘接到另一台宿主机,以相同的池 ID 声明,那台 node 成为成员,见池换宿主。
- 盘也没了:用
kibo storage-pool declare-lost。
overcommit
node 的 [resources] 只写宿主能给 VM 的 CPU 与内存。超卖由 ctrl 的倍数表达:放置用的可调度量等于 node 报告的量乘以倍数。改倍数不需要重启 node:
kibo node overcommit get
kibo node overcommit set-default --cpu 4
kibo node overcommit set "$node_id" --cpu 2.5 --memory 0.9
kibo node overcommit set "$node_id" --cpu default- 倍数写成十进制,最多三位小数,CPU 与内存都在 0 到 16 之间。
- 内存倍数大于 1 时,guest 实际用到的内存可能超过宿主内存。宿主内存耗尽时内核杀掉其中一台 VM,ctrl 随后自行停止它的 Workspace,调用方直接
start即可;未落盘的写入可能丢失。KiboVM 的 guest 内存要等进程完全退出才释放,这段时间里内核可能再杀一个进程。按长时间运行后的实际用量设内存倍数,见下面的 Host usage。 - 宿主可用内存低于总内存的 10% 时,node 判定内存紧张:拒绝新建 Workspace,ctrl 立即改为放到别的 node,所有 node 都放不下时返回
resource_exhausted。可用内存回到 15% 以上后恢复。已有的 Workspace 不受影响。 set-default改全集群的默认值,期望版本是get显示的version。set改一个 node 的覆盖,期望版本是它的registration_version;default清除这一项的覆盖,回到全集群默认。- 两条命令都只改给出的那一项,另一项保持当前值。显式传
--command-id时必须同时传--expected-version和两个倍数,这样重放的输入不依赖执行时读到的值。 - 调低到已分配量以下时,这个 node 不再接收新的 Workspace,已有的照常运行,不会被驱逐。
- 新值送到 node、node 确认之前,ctrl 不向这个 node 放置,通常不到一秒。node 没有确认时,ctrl 断开它的控制连接,重连后再送一次。
kibo node get 的「Host usage」是实际用量,只用于查看,不参与放置:
| 项 | 内容 |
|---|---|
VM CPU、VM memory | 全部 VM 占用的 CPU 与 guest 实际用过的内存 |
Memory available | 宿主可用内存,含可以回收的缓存 |
Memory tight | node 是否判定宿主内存紧张、从何时起;紧张期间不接收新的 Workspace。kibo node list 的 MEM_TIGHT 列显示同一件事 |
CPU idle | 宿主 CPU 的空闲比例 |
CPU pressure、Memory pressure | 最近 60 秒里任务因等待 CPU 或内存而停顿的时间占比;some 是至少一个任务在等,full 是全部任务都在等 |
- node 每 10 秒采样一次,ctrl 每次对账时(60 秒)取回最新一次,所以读数最多落后约一分钟。
- 读不到的项显示
-,不是 0。还没有启动过 VM 的 node 没有 VM 两项。 - VM 两项统计的是整台宿主上的 VM。一台宿主只运行一个 node 时,它就是这个 node 的 VM。
- guest 用过的内存不会还给宿主,跑得越久的 VM,VM memory 越接近它申请的内存。按实际用量调内存倍数时,看长时间运行后的读数。
Workspace 在哪台 node 上
kibo workspace list 按 node 或 Instance 列出正在执行的 Workspace,kibo workspace get 显示一个 Workspace 所在的 node:
kibo workspace list --node node-a
kibo workspace list --instance inst-01k6…
kibo workspace get ws-01k6…| 写法 | 结果 |
|---|---|
workspace list --node | 这台 node 上正在执行的全部 Workspace |
workspace list --instance | 以这个 Instance 执行的 Workspace。宿主上的目录、进程参数与日志给出的是 Instance ID,用它反查 Workspace |
workspace get | Node 一行是所在 node,--wide 再加一行当前 Instance |
- 表格与普通的
workspace list相同,--wide另加INSTANCE与NODE两列。Instance 每次启动换一个新的。 - 只列出现在有执行的 Workspace。已停止、已删除和还没放置到 node 上的 Workspace 没有 node,
workspace get显示-。 - 不再是当前 Instance 的 ID 查不到任何行,与从未存在过的 ID 一样。
--node与--instance互斥,也不能与--state、--label等过滤同时使用。node 不存在时退出码为12。kibo先读一页位置,再逐个读取 Workspace;两次读取之间被删除的 Workspace 不出现。-q --all只输出 Workspace ID,一行一个,可以交给脚本逐个处理。- 连到没有位置查询的旧 ctrl 时,
workspace get的Node显示unknown,命令本身照常成功。
把 Workspace 放到指定 node
--node 把一次创建或启动固定到一台 node,kibo workspace move 把 Workspace 停止后在另一台 node 上启动:
kibo workspace create --template kibotos-coding --node node-c
kibo workspace start ws-01k6… --node node-b
kibo workspace move ws-01k6… --node node-b- 只有这一台是候选。它必须像任何放置一样接收这个 Workspace:未 drain、就绪、剩余容量够,并接入 Workspace 的 Volume 与可写层所在的池。不满足时创建或启动失败,不会改放到别的 node。
- 只对这一次放置生效。Workspace 不记住这台 node,以后不带
--node的启动照常由调度决定。 - drain 照样挡住指定放置。冒烟一台新 node 要先取消它的 drain,其间调度也可能把别的 Workspace 放上去。
- 创建时,随创建的 Volume 与可写层落在这台 node 的默认池。对象在 node 的私有池里时,Workspace 以后只能在这台 node 上启动;要能换 node,用多台 node 共用的池,见 storage-pool。
workspace move 依次做三件事:
| 步骤 | 做什么 | 不满足时 |
|---|---|---|
| 核对 | 读 Volume 与可写层所在的池,以及目标 node 报告可用的池 | 有对象在目标 node 接不到的池里,或正在搬迁:退出,Workspace 不变 |
| 停止 | Workspace 为 AVAILABLE 时正常停止;STOPPED 与 FAILED 跳过 | 停止失败:按停止的错误退出 |
| 启动 | 在目标 node 上启动 | Workspace 不再运行,错误给出重新启动的命令,即 kibo workspace start ws-01k6… --node node-b |
- 没有热迁移。停止与启动和平常一样,内存与进程不保留。
- Workspace 已经运行在目标 node 上时直接成功,不停止。
--command-id给出时,停止与启动的命令 ID 是它加上/stop与/start。同一条命令再运行一次,接着处理没完成的那一步。