2 分•作者: gbxk•大约 1 个月前
大家好,我是 Gary。<p>今天我想介绍 k7d,这是一个遵循 Apache 2.0 协议、用 Rust 编写的精简 VMM + shim,它实现了以前不可能的功能:能够快速克隆正在运行的虚拟化多节点 Kubernetes 集群,并且在克隆过程中保持进行中的连接。
<p>一个包含 3 个 VM 节点的 K8s 集群可以在 105 毫秒内完成克隆,在 64GB RAM 的机器上,一个包含 3 个 VM 的集群可以进行 50 次克隆,耗时 4.1 秒。
<p>我在这里有两个目标:
<p>1) 实现大规模 GRPO/RL 训练的 AI 在 Kubernetes 基础设施上运行,我认为这是一个非常适合推理训练的平台,除了训练一个真正有用的能力。这不仅需要快速的 episode 重置(因为在 RL 后期训练中你需要数万次多轮交互),而且快速克隆也能极大地受益于并行分支探索、回滚和剪枝,从而在 RL 训练过程中进行。忠实的克隆也能为 GRPO 的 G 提供字节相同的起点,从而减少组间的方差。
<p>2) 为我的另一个项目 K7 实现 <3 秒的 VM 快照暂停/恢复/克隆沙箱,该项目提供大规模 VM 沙箱的自托管基础设施,具有用户友好的 CLI/API/Python SDK,并且是 Kubernetes 原生的。
<p>除此之外,k7d 还具备以下特点:
<p>- 树形 API 进行资源管理:正如你所料,在克隆时,即使有优化的写时复制(CoW)页面共享,你也需要妥善管理你的资源(内存+磁盘),因此你需要知道如何在运行时进行驱逐。所以我设计了树形逻辑来跟踪子页面与父页面的共享情况,让你的 AI 代理可以保护有前景的树分支,驱逐没有前景的分支,或者在资源紧张时让 LRU(最近最少使用)之类的逻辑自动驱逐。这种基于树的逻辑既适用于单 VM 沙箱,也适用于多 VM 集群及其自身的 Linux 网桥。
<p>- 形式化验证:当然不是全部,但 k7d 的部分关键子模块已经过形式化验证:我使用 Kani 对不安全路径中的内存算术进行验证,并使用 Aeneas(带有 Lean 后端)来形式化证明上述基于树的逻辑,以确保驱逐永远不会释放被活动后代引用的页面。
<p>- 将延迟作为 CI:我严格跟踪大多数重要操作的延迟,并通过一套集成测试来持续检查/强制执行。
<p>我确实努力避免自己构建 VMM,最初我为 K7 构建了一个不同于我最初的“kfd”(Kata + Firecracker + Devmapper-snapshotter over LVM thin-pool)的后端,我称之为“kql”(Kata + Qemu + Longhorn)。如果你熟悉这个技术栈,你就会立刻明白:Longhorn 非常适合跨节点复制,所以我用它来跨节点复制我的快照,这样“快照恢复”总是有效/高可用。这里使用 Qemu 是因为 Longhorn 的块存储要求与 Firecracker 不兼容,Firecracker 需要 Devmapper-snapshotter,而我不想自己构建跨节点复制逻辑。
<p>但是这个“kql”后端由于 Longhorn 的构建方式,克隆速度为 45 秒,这对于要求 K7 实现快速克隆的用户来说太慢了。
<p>因此,这促使我转向 k7d,它被命名为“k7 的守护进程”,它是一个独立的、原生的 VMM 和 shim,同时取代了 Firecracker/Qemu 和 Kata。
<p>这使得 K7 中的 VM 沙箱可以在 2-3 秒内完成克隆,其中大部分延迟是 kubelet 的开销,因为在 VMM 层面,热克隆实际上只需要 5 毫秒。
<p>一个安全权衡:守护进程必须在同一棵树的分支之间共享:这是设计使然。因此,你失去了 Firecracker 为每个 VM 提供的 Jailer。但我可以为每棵树重建一个类似的 Jailer,当一棵树不跨租户共享时,例如在使用分支进行 RL 训练时,这已经足够了。这只是针对与 Firecracker 不同的目标进行了优化。
<p>代码库有意设计得足够精简,便于审计(VMM + shim < 30k 行代码),并且我在 README 的顶部链接了一个深入的博客文章系列。
<p>我希望大家会喜欢它,我也非常欢迎贡献者和批评者。
<p>谢谢!