Learning Kuasar
- 1: 介绍
- 1.1: Kuasar介绍
- 1.2: Kuasar背景
- 1.3: codewiki上的介绍
- 1.3.1: kuasar介绍
- 1.3.2: 容器运行时集成
- 1.3.3: MicroVM 沙箱
- 1.4: Kuasar资料收集
- 2: 快速开始
- 2.1: 安装
- 3: 组件
- 4: 流程
1 - 介绍
1.1 - Kuasar介绍
https://github.com/skyao/kuasar
介绍
Kuasar 是一款高效的容器运行时,通过支持多种沙箱技术提供云原生全场景容器解决方案。它采用 Rust 语言编写,基于沙箱 API 提供标准沙箱抽象层。此外,Kuasar 还提供优化框架以加速容器启动并减少不必要的开销。
在当前发展阶段,没有任何单一的基础容器技术能够完美支持所有云原生场景的需求。我们的目标是提供更优的解决方案,以管理和平衡企业对容器隔离性、安全性、通用性、运行速度及资源消耗等方面的需求。
kuasar的优点
在容器领域,沙盒是一种用于将容器进程相互隔离以及与操作系统本身隔离的技术。随着沙盒 API 的引入,沙盒已成为 containerd 中的第一类公民。随着容器领域中越来越多的沙盒技术出现,预计将提出一个名为“沙盒管理器”的管理服务。
Kuasar 支持多种类型的沙盒管理器,使用户能够根据应用需求为每个应用选择最合适的沙盒管理器。
与其他容器运行时相比,Kuasar 具有以下优势:
- 统一沙盒抽象:沙盒在 Kuasar 中是一流公民,因为 Kuasar 完全基于沙盒 API 构建,该 API 由 containerd 社区于 2022 年 10 月预览。Kuasar 充分利用了沙盒 API 的优势,提供了一种统一的沙盒访问和管理方式,并提高了沙盒运维效率。
- 多沙盒共置:Kuasar 内置支持主流沙盒,允许多种类型的沙盒在单个节点上运行。Kuasar 能够平衡用户对安全隔离、快速启动和标准化的需求,并使无服务器节点资源池满足各种云原生场景要求。
- 优化框架:通过移除所有暂停容器并将 shim 进程替换为单个驻留沙盒器进程,Kuasar 进行了优化,带来了 1:N 进程管理模型,其性能优于当前的 1:1 shim v2 进程模型。基准测试结果显示,Kuasar 的沙盒启动速度提升 2 倍,而管理资源开销降低了 99%。更多详情请参考性能。
- 开放与中立:Kuasar 致力于构建一个开放且兼容的多沙盒技术生态系统。得益于沙盒 API,集成沙盒技术更加便捷且节省时间。Kuasar 对沙盒技术保持开放和中立的态度,因此所有沙盒技术都受到欢迎。目前,Kuasar 项目正在与 WasmEdge、openEuler 和 QuarkContainers 等开源社区和项目合作。
Kuasar 的技术优势主要包括:
-
灵活的插件沙盒扩展能力
Kuasar 具有灵活的插件沙盒扩展能力。它提供了一个更对开发者友好的沙盒访问框架,使得主流沙盒的持续集成成为可能。
-
清晰统一的沙盒定义
Kuasar 基于最新的沙盒 API,具有清晰统一的沙盒定义。沙盒的管理逻辑与容器分离,不再像以前那样耦合在一起。而且这将得到上游 containerd 社区的原生支持。
-
简化容器 API 调用链
Kuasar 拥有简化的容器 API 调用链。如您所见,容器运行时可以在无需像以前那样在“shim”中进行额外转换的情况下管理容器。
-
高效的 Kuasar 沙盒器
Kuasar 拥有高效的沙盒器和优化的框架:
- 它的进程是驻留的,这意味着启动时间更短。
- 它的进程模块是 1:N,这意味着随着容器数量的增加,其资源开销不会增加。
- 它是用 Rust 编写的,这意味着高性能、高安全性和低开销。
-
消失的“pause”容器
Kuasar 移除“暂停”容器的原因是安全容器是一个自然的 Pod 模型。这种优化减少了由暂停容器引入的资源开销和启动时间。
功能
支持的沙箱
| Sandboxer | Sandbox | Status |
|---|---|---|
| MicroVM | Cloud Hypervisor | Supported |
| QEMU | Supported | |
| Firecracker | Planned in 2025 | |
| StratoVirt | Supported | |
| Wasm | WasmEdge | Supported |
| Wasmtime | Supported | |
| App Kernel | Quark | Supported |
| runC | runC | Supported |
架构

Kuasar 中的沙盒器使用各自的容器隔离技术,并且它们也是基于新的沙盒插件机制构建的 containerd 外部插件。关于沙盒器插件的讨论已在 containerd 问题中提出,并在该评论中附有社区会议记录和幻灯片。现在这一功能已被纳入 2.0 里程碑。
目前,Kuasar 提供三种类型的沙盒器——MicroVM 沙盒器、App Kernel 沙盒器和 Wasm 沙盒器——所有这些都被证明在多租户环境中是安全的隔离技术。沙盒器的一般架构由两个模块组成:一个模块实现沙盒 API 以管理沙盒的生命周期,另一个模块实现任务 API 以处理与容器相关的操作。
MicroVM 沙盒器
在 microVM 沙盒场景中,VM 进程提供基于开源 VMM(虚拟机管理器)如 Cloud Hypervisor、StratoVirt、Firecracker 和 QEMU 的完整虚拟机和 Linux 内核。所有这些虚拟机都必须在支持虚拟化的节点上运行,否则将无法工作!因此,MicroVM 沙盒器的 vmm-sandboxer 负责启动虚拟机并调用 API,而 vmm-task 作为虚拟机中的初始化进程,扮演运行容器进程的角色。容器 IO 可以通过 vsock 或 uds 导出。
microVM 沙盒器避免了在主机上运行 shim 进程的必要性,带来了一种更干净、更易于管理的架构,每个 pod 只有一个进程。

App Kernel Sandboxer
App Kernel 沙盒启动 KVM 虚拟机和 guest 内核,无需任何应用级虚拟机管理程序或 Linux 内核。这允许针对启动过程进行定制优化,减少内存开销,并提高 IO 和网络性能。此类应用内核沙盒的例子包括 gVisor 和 Quark。
Quark 是一个应用内核沙盒,它使用自己的虚拟机管理程序 QVisor 和定制的内核 QKernel 。通过对这些组件进行定制修改,Quark 可以实现显著的性能提升。
应用内核沙盒器 quark-sandboxer 启动 Qvisor 并创建一个名为 Qkernel 的应用内核。每当 containerd 需要在沙盒中启动容器时, QVisor 中的 quark-task 将调用 Qkernel 来启动一个新容器。同一 Pod 内的所有容器将在同一个进程中运行。

Wasm Sandboxer
Wasm 沙盒,如 WasmEdge 或 Wasmtime,非常轻量级,但目前可能对某些应用存在限制。 wasm-sandboxer 和 wasm-task 在 WebAssembly 运行时中启动容器。每当 containerd 需要在沙盒中启动容器时, wasm-task 会创建新进程,启动新的 WasmEdge 运行时,并在其中运行 Wasm 代码。同一 Pod 中的所有容器将与 wasm-task 进程共享相同的 Namespace/Cgroup 资源。

Runc Sandboxer
除了安全容器,Kuasar 还为 runC 容器提供了运行能力。为了生成一个独立的命名空间, runc-sandboxer 通过双重克隆创建一个轻微的过程,然后成为 PID 1。基于这个命名空间, runc-task 可以创建容器进程并加入该命名空间。如果容器需要私有命名空间,它会为自己 unshare 一个新的命名空间。

1.2 - Kuasar背景
https://kuasar.io/docs/background/sandbox-rise/
大约在 2018 年,各种云原生容器隔离技术逐渐出现。我们将这项技术称为“沙盒”。
而沙盒是一个自然的 POD 模型。它为一组容器提供了一个隔离环境。存在一些典型的沙盒:microVM 沙盒、application-kernel沙盒和 WASM 沙盒。
它们是为不同云原生场景下的企业需求而生的,因此具有不同的优势维度。

如您所见,microVM 沙盒适用于安全且通用的多租户情况。应用内核沙盒适用于高效且通用的多租户情况。WASM 沙盒适用于非常轻量级任务的情况,例如函数计算。

痛点与趋势
现在,主流云厂商在其产品中使用了多种沙箱技术。但没有任何单一的容器运行时能够同时直接运行上述沙箱。
因此,用户不得不维护多个容器运行时来管理不同的沙箱,这增加了运维(operation and maintenance)的压力。
此外,由于当前的容器运行时缺乏平滑的演进路径,大多数企业仍然停滞不前,无法将其产品的最新沙箱技术整合到产品中。
去年,主流容器运行时‘containerd’在社区呼声下,在其预览版本中引入了沙箱 API。
我们相当确定沙盒即将到来,它应该成为容器运行时的一个新的第一类公民。
我们需要一个多沙盒容器运行时。
它使沙盒成为一等公民。
它自然支持主流沙盒技术。
它有一个插件、可扩展和可进化的机制。
所以这就是 Kuasar 诞生的原因。
1.3.1 - kuasar介绍
https://codewiki.google/github.com/kuasar-io/kuasar#introduction-to-kuasar-sandboxes
Kuasar 是一个多沙盒容器运行时,它统一了多种容器隔离技术于一致的 Sandbox API 框架下。它管理 MicroVM、App Kernel、WebAssembly(Wasm)和 runC 沙盒。这种做法在安全性和性能之间为云原生应用实现了平衡。
Kuasar 与容器运行时集成,特别是通过 containerd 的 shim proxy 进行集成。这个代理充当 CRI runtime V2 backend ,在 containerd 和 Kuasar 的各种沙盒进程之间调解 Sandbox API 和 Task API 请求。使用 Unix 域套接字(UDS)和 VSock 进行高效通信。更多详情请参考容器运行时集成。
Kuasar 提供不同的沙盒类型,每个都针对不同的隔离需求:
- MicroVM Sandbox (
VMM): 这个沙盒编排虚拟机环境,抽象设备管理、cgroup 控制、网络和存储。它通过在专用虚拟机中运行工作负载提供强隔离。 - App Kernel Sandbox (
Quark):quark-sandboxer守护进程使用应用级虚拟机管理器管理容器化环境。这种设置利用定制内核优化性能。 - WebAssembly Sandbox (
Wasm):wasm-sandboxer在 WebAssembly 运行时中启动容器,例如Wasmtime和WasmEdge。这实现了 Wasm 模块的效率和可移植性执行。 runCSandbox:runc-sandboxer提供基于runC的容器功能,创建隔离的命名空间并管理容器生命周期。
单个居民 sandboxer 进程可以管理多个容器,采用 1:N 进程管理模型。与传统的 1:1 shim v2 模型相比,这减少了开销,并消除了 pause containers 。该项目使用 Rust 实现了许多组件,以提高效率和内存安全性。有关这些功能的更多信息,请参阅多沙盒功能概述和 Kuasar 的核心架构和设计原则。
Kuasar 沙盒介绍
Kuasar 是一个多沙盒容器运行时,旨在为各种部署场景提供云原生解决方案。它主要使用 Rust 实现,将多种容器隔离技术统一在一致的 Sandbox API 框架下,并借鉴了预览的 containerd API 的灵感。这种设计使 Kuasar 能够管理多种沙盒类型,包括 MicroVM、App Kernel、Wasm 和 runC 沙盒,在安全性、启动速度和标准化之间取得平衡。该项目的架构通过移除 pause containers 并采用 1:N 进程管理模型来优化性能,其中单个驻留的 sandboxer 进程可以管理多个容器,与传统 1:1 shim v2 模型相比,从而降低了开销。
Kuasar 的设计核心围绕几个关键组件和架构原则。它通过专门的沙盒器支持不同的隔离技术。例如,MicroVM 沙盒器( vmm-sandboxer ),位于 vmm 目录中,负责协调虚拟机环境,抽象设备管理、cgroup 控制、网络和存储。类似地,App Kernel 沙盒器( quark-sandboxer )在 quark 中,使用应用级虚拟机管理程序管理容器化环境。Wasm 沙盒器( wasm-sandboxer ),位于 wasm ,处理 WebAssembly 沙盒和容器,并与 Wasmtime 和 WasmEdge 等运行时集成。最后, runC 沙盒器( runc-sandboxer )在 runc 中,管理基于传统 runC 的容器沙盒。

Kuasar 与容器编排系统的集成,特别是与 containerd 的集成,通过专门的 shim 实现。这些 shim 位于 shim 目录中,作为代理代理,在 containerd 和相应的 Kuasar 沙盒进程之间转发 Sandbox API 和 Task API 请求。这种模块化设计确保 Kuasar 能够扩展其功能到不同的容器环境,同时保持与现有容器生态系统的兼容性。Kuasar 组件的整体构建、安装和测试过程由 Makefile 在 Makefile 管理,以及位于 scripts 的补充脚本处理,从编译自定义 containerd 到配置超虚拟机和客户操作系统镜像,涵盖了所有方面。有关构建和安装的更多详细信息,请参阅构建和安装过程。
Kuasar 的核心架构和设计原则
Kuasar 是一个用 Rust 编写的有效容器运行时,旨在通过多种沙盒技术为各种场景提供云原生解决方案。其核心架构在一致的 Sandbox API 下统一了多种隔离技术,实现了安全、启动速度和标准化的平衡。
Kuasar 的一项基础设计原则是 Multi-Sandbox Colocation ,它允许不同的沙盒类型——MicroVM、App Kernel、Wasm 和 runC ——在单个节点上并发运行。这种方法使用户能够为他们的工作负载选择最合适的隔离级别。例如,MicroVM 沙盒提供强隔离,适合不可信的工作负载,而 runC 沙盒为可信应用提供轻量级的容器化。 Sandbox API ,正如 containerd 所预览的,作为统一接口,抽象掉了每种底层隔离技术的复杂性。这为容器运行时提供了一个一致的管理层,更多细节请参考容器运行时集成。
Kuasar 的 Optimized Framework 优先考虑性能和资源效率。一个关键的设计选择是移除 pause containers ,并将多个 shim 进程替换为单个驻留的 sandboxer 进程。这形成了一个 1:N 进程管理模型,其中单个 sandboxer 管理多个容器,与传统 1:1 shim v2 模型相比显著降低了开销。这种架构在不同沙盒类型中始终如一地实施。例如, vmm-sandboxer 编排虚拟机环境, quark-sandboxer 管理 App Kernel 沙盒, wasm-sandboxer 处理 Wasm 容器。这些沙盒器通过专用适配器与 containerd 通信,例如在 shim 中找到的适配器,它们转发 Sandbox API 和 Task API 请求。该项目还维护一个路线图,概述了未来的增强功能和特性,表明持续关注优化和新功能。
整个 Kuasar 项目是用 Rust 语言实现的,这一选择强调了效率、内存安全性和并发性。这一点在主 (root) 目录中的源代码组织结构中表现得十分明显,其中核心组件、文档以及每种沙盒类型的工具都被系统地组织起来。在 Makefile 的 Makefile 中,这些组件的构建、安装和测试被协调管理,展示了一个模块化和可配置的构建过程。该项目还致力于构建一个开放和中立生态系统,正如在 README.md 的 README.md 中所强调的那样,该生态系统旨在集成多样的沙盒技术并促进社区贡献,具体细节在 CONTRIBUTING.md 中有详细说明。
多沙盒功能概述
Kuasar 将多种隔离技术统一在一致的 Sandbox API 框架下,使多种沙盒类型能在单个节点上并发运行。这种方法在云原生环境中平衡了安全性、启动速度和标准化。其核心架构,如《Kuasar 核心架构与设计原则》所述,利用单个驻留的 sandboxer 进程来管理多个容器,通过移除 pause containers 优化资源使用并简化进程管理模型。
Kuasar 的多沙盒功能包括:
- MicroVM Sandbox (
VMM): 该沙盒利用开源虚拟机监视器(VMM)如Cloud Hypervisor、QEMU和StratoVirt来协调虚拟机环境。vmm-sandboxer负责设备管理、cgroup 控制、网络和存储。在这些虚拟机中,vmm-task组件作为init进程运行,管理容器和进程的生命周期。更多信息请参阅 微虚拟机沙盒(VMM)。 - App Kernel Sandbox (
Quark):quark-sandboxer守护进程使用应用级虚拟机管理程序管理容器化沙盒环境。这种设置利用定制内核为应用内核工作负载提供优化性能。更多细节可在 应用内核沙盒(Quark) 中找到。 - WebAssembly Sandbox (
Wasm):wasm-sandboxer在 WebAssembly 运行时(如Wasmtime和WasmEdge)中启动容器。这使 Wasm 模块在容器化环境中能够高效和便携地执行。Kuasar 的containerd-shim集成特别利用这些运行时来执行 Wasm 模块和管理资源限制。更多信息请参阅 WebAssembly 沙盒(Wasm)。 runCSandbox:runc-sandboxer提供基于runC的容器功能,通过双重分叉机制创建隔离的命名空间。这些命名空间内的runc-task管理容器进程,确保与 OCI 规范兼容。更多详情请参阅runC沙盒。
这些沙盒类型通过一个 shim 代理与 containerd 集成,该代理充当 CRI runtime V2 backend 。这个代理在 containerd 和相应的 Kuasar 沙盒进程之间转发 Sandbox API 和 Task API 请求,使用 Unix 域套接字(UDS)和 VSock 进行进程间通信。有关此集成的详细说明,请参阅容器运行时集成。
构建和安装过程
Kuasar 的构建和安装过程主要通过一个 Makefile 和一套 shell 脚本进行协调,这些工具促进了其各种沙盒组件、定制容器运行时和客操作系统实体的编译和部署。该基础设施支持不同的虚拟机管理程序、WebAssembly 运行时和内核版本。
中央 Makefile ( Makefile )管理整个构建生命周期,包括编译 vmm 、 wasm 、 quark 和 runc 沙盒器。它通过 HYPERVISOR (默认值为 cloud_hypervisor )、 GUESTOS_IMAGE (默认值为 centos )、 WASM_RUNTIME (默认值为 wasmedge )和 KERNEL_VERSION 等变量实现灵活配置。这些变量决定了构建哪些与 VMM 相关的组件、使用哪种类型的客户操作系统镜像以及集成特定的 WebAssembly 运行时。 Makefile 还负责将编译后的二进制文件和相关 systemd 服务文件安装到标准系统目录中。
与 Makefile 相补充, scripts 目录包含专门的 shell 脚本。 scripts/build 子目录专注于准备关键依赖。例如, build-containerd.sh ( scripts/build/build-containerd.sh )自动化编译 Kuasar 特定的 containerd 二进制文件,并将其配置为与 Kuasar 的各种沙盒类型(如 kuasar-runc 、 kuasar-vmm 、 kuasar-quark 、 kuasar-wasm )作为 proxy_plugins 集成。另一个脚本 cargo-vendor.sh ( scripts/build/cargo-vendor.sh )通过为 Kuasar 的子项目提供 Rust 依赖,确保可重复构建,允许离线编译。
scripts/install 子目录提供了部署 Kuasar 的详细脚本,特别是 VMM 沙盒器。这些脚本针对不同场景,为 x86_64 和 aarch64 架构提供基于源代码的编译和基于二进制的安装。例如, build-and-install-kuasar-vmm.sh ( scripts/install/build-and-install-kuasar-vmm.sh )通过编译 Cloud-Hypervisor (Kuasar VMM 沙盒器)、Kuasar 特有的 containerd 和 virtiofsd 从源代码进行完整安装。它还处理 crictl 的安装和配置,利用 Docker 或 Podman 等容器运行时进行隔离构建。为了在 x86_64 上更快部署, install-kuasar-vmm-x86.sh ( scripts/install/install-kuasar-vmm-x86.sh )使用相同组件的预编译二进制文件。两种安装方法都包括下载组件的校验和验证,并提供交互式提示以获取用户确认。一个专门的 uninstall-kuasar-vmm.sh ( scripts/install/uninstall-kuasar-vmm.sh )脚本提供了一种全面移除 Kuasar 相关组件的方式,包括停止 systemd 服务、删除二进制文件以及清理配置文件。
此外,VMM 组件在 vmm/scripts 中包含用于生成客机操作系统根文件系统和镜像的专业脚本。这涉及创建与 Kata Containers 兼容的镜像,并构建基于 CentOS 的根文件系统。 vmm/scripts/kernel 中的脚本用于为各种 VMM(如 Cloud Hypervisor、QEMU 和 StratoVirt)定制 Linux 内核镜像,并为 Kuasar 安全容器定制内核,通常针对最小内存占用进行优化。
文档与社区资源
Kuasar 提供了各种资源来促进理解、集成和社区参与。
在 docs 目录中提供全面的文档。这包括有关将 Kuasar 与 containerd 等容器运行时集成的详细指南,概述了 shim proxy 的功能以及 vmm 、 quark 和 wasm 沙盒器的配置。还提供了针对不同虚拟机管理程序(如 QEMU 和 StratoVirt)构建、安装和配置 Kuasar 的具体说明。此外,文档还提供了在 Kubernetes 中部署基于 Wasm 的大型语言模型(LLM)推理应用程序的指导,展示了 Kuasar Wasm 能力的实际应用。
除了文档之外,该项目通过多种途径鼓励社区参与。 ROADMAP.md 文件概述了核心框架、测试、Kubernetes 功能支持和安全方面的未来开发计划及改进。贡献由 CONTRIBUTING.md 指导,其中详细说明了工作流程、代码审查过程和提交信息格式标准。 CODE_OF_CONDUCT.md 文件确立了社区期望,并参考了 CNCF 行为准则。 ADOPTERS.md 中提供了采用 Kuasar 的组织和项目的相关信息,而 MAINTAINERS.md 列出了官方项目维护者和团队。变更和版本历史计划在 CHANGELOG 目录中进行跟踪。
1.3.2 - 容器运行时集成
https://codewiki.google/github.com/kuasar-io/kuasar#container-runtime-integration
Kuasar 与容器运行时(特别是 containerd )通过一个专门的 shim proxy 进行集成。这个代理充当一个 CRI runtime V2 backend ,在 containerd 和 Kuasar 的各种沙箱进程之间中继请求。这个 shim 的主要功能是将 Sandbox API 请求转发到相应的 Kuasar 沙箱进程(例如 VMM 或 Wasm 沙箱进程),并将 Task API 请求转发到低级任务器,从而将复杂的处理工作从代理本身卸载。
shim 组件是使 containerd 能够协调 Kuasar 的多样化沙盒的核心,包括 MicroVMs ( kuasar-vmm ) 和 WebAssembly 模块 ( kuasar-wasm )。针对这些不同环境有特定的 shim 二进制文件,例如用于 MicroVMs 的 containerd-shim-kuasar-vmm-v2 和用于 Wasm 工作负载的 containerd-shim-kuasar-wasm-v2 。这些适配器被构建并安装到系统中,通常在 /usr/local/bin/ 中,使用位于 shim/Makefile 的 Makefile 进行构建和安装。
containerd 与 Kuasar 沙盒进程之间的交互依赖于进程间通信机制。对于 kuasar-vmm ,通信通常通过 VSock 进行,这适用于虚拟化环境。对于 kuasar-wasm ,通常使用 Unix 域套接字(UDS)进行高效通信。 shim 负责建立和管理这些通信通道。
要集成 Kuasar 与 containerd ,需要在 containerd 的配置文件中进行特定修改,该文件通常位于 /etc/containerd/config.toml 。这些修改定义了 runtime_type 和 sandbox_mode 设置,用于 kuasar-vmm 和 kuasar-wasm 运行时,指定 containerd 如何调用 Kuasar 的 shims。此外,必须使用 ENABLE_CRI_SANDBOXES=1 环境变量启动 containerd ,以启用 containerd Sandbox API ,这对 Kuasar 的运行至关重要。
提供有关构建、安装和配置 Kuasar shim 和 containerd 的全面指南,详细说明了先决条件和必要的系统调整。有关 shim 内部结构的更多详细信息,请参阅 Shim 代理架构和通信机制。
代理架构和通信机制
Kuasar shim 作为 CRI runtime V2 backend ,在 containerd 和 Kuasar 的 sandboxer 进程之间进行通信中介。这种架构允许 containerd 通过一致接口管理多样化的 Kuasar 沙盒,包括 MicroVM 和 WebAssembly (Wasm) 环境。Shim 主要作为代理,将 Sandbox API 请求转发到相应的 sandboxer (例如 vmm-sandboxer 或 wasm-sandboxer ),将 Task API 请求转发到低级的 tasker ,从而最小化 Shim 对这些请求的内部处理。
沙盒的核心功能通过 Service<T> 结构实现,该结构遵循 Shim 特性。这个 Service 包含一个 KuasarServer<T> ,封装了与 Kuasar 组件交互的业务逻辑。这个 KuasarServer 又包括一个用于沙盒操作的 SandboxHandler<T> 和一个用于管理任务的 TaskHandler 。
containerd 、 shim 以及 Kuasar 的 sandboxer 和 tasker 进程之间的进程间通信(IPC)通过不同的传输机制实现。对于 VMM 工作负载, containerd-shim-kuasar-vmm-v2 利用 VSockTransport ,实现通过虚拟套接字进行通信,这在虚拟化环境中很常见。这对于使用 MicroVMs 隔离容器的场景尤其相关。 shim/src/io.rs 中的 VSockTransport 管理虚拟套接字端口分配以防止冲突,并处理 containerd 管道和虚拟套接字流之间的数据传输。
对于 Wasm 工作负载, containerd-shim-kuasar-wasm-v2 采用 UdsTransport (Unix 域套接字)。这适用于 Wasm 沙盒可能不需要完整虚拟机的情况,可在主机系统内部提供高效的 IPC。 shim/src/io.rs 中的 UdsTransport 直接使用提供的管道路径, containerd 负责 UDS I/O 复制。
两个 shim 都建立与 Kuasar sandboxer 和 tasker 进程的连接。 shim/src/sandbox.rs 中的 SandboxHandler 负责将 containerd-shim TTRPC 请求转换为 containerd-sandbox v2 控制器的 gRPC 调用,管理从创建到关闭的沙盒的完整生命周期。 shim/src/task.rs 中的 TaskHandler 作为代理,将 containerd 垫片 Task API 调用转发到底层 TaskClient ,并与 SandboxHandler 协调容器和进程生命周期管理以及资源分配。这种架构确保了 containerd 可以无缝地与 Kuasar 的各种沙盒技术交互。有关 containerd 集成的更多详细信息,请参阅容器运行时集成。
构建与安装 Kuasar Shim
Kuasar containerd shim 通过位于 shim/Makefile 的 Makefile 进行构建和安装。这个 Makefile 协调编译和安装两个不同的 shim 二进制文件: containerd-shim-kuasar-vmm-v2 和 containerd-shim-kuasar-wasm-v2 。这些二进制文件使 containerd 能够分别与 Kuasar 的 VMM 和 Wasm 运行时集成。构建过程利用 cargo build --release 创建优化的可执行文件。构建完成后, install 目标将这些二进制文件移动到系统的 /usr/local/bin/ 目录,确保它们对 containerd 可用。
与 shim 构建互补,Kuasar 项目还包含一个用于构建自定义 containerd 二进制文件的脚本。该脚本位于 scripts/build/build-containerd.sh ,克隆 containerd 仓库的 Kuasar 特定分支,进行编译,并生成 config.toml 文件。此配置文件对于集成 Kuasar 运行时至关重要,它定义了 runtime_type 的设置,用于 kuasar-runc 、 kuasar-vmm 、 kuasar-quark 和 kuasar-wasm ,并配置 proxy_plugins 以促进与各自的沙盒服务通信。这种自定义的 containerd 设置对于确保 shim 能够正确地与 Kuasar 的多沙盒功能交互至关重要。若要深入了解这些 shim 如何与 containerd 集成,请参阅 Kuasar 运行时的 Containerd 配置。
shim 服务和沙盒/任务管理
Kuasar 中的 containerd shim 服务充当关键的中介,将来自 containerd 的请求转换为由 Kuasar 的沙盒器和任务服务管理的操作。该服务主要由 Service<T> 结构实现,该结构遵循 containerd 的 Shim 特性。 Service<T> 利用一个 KuasarServer<T> 实例来封装与 Kuasar 后端交互所需的应用逻辑。
KuasarServer<T> 的核心包含两个关键组件: SandboxHandler<T> 和 TaskHandler 。 SandboxHandler<T> 负责协调沙盒的生命周期。当 containerd 请求创建、启动、停止或删除沙盒等操作时, SandboxHandler 接收这些 TTRPC 请求,并将它们转换为对 containerd-sandbox v2 控制器的相应 gRPC 调用。这种委托确保实际的沙盒管理,包括资源分配和隔离,由 Kuasar 沙盒器处理。 SandboxHandler 还管理沙盒的本地文件系统设置和清理,例如创建根目录和挂载共享内存,具体细节请参见沙盒状态管理和持久化。
同样地,TaskHandler 负责管理沙箱内任务(容器和进程)的生命周期。它充当代理角色,将 containerd 适配层的任务 API 调用转发至底层的 TaskClient,后者再与 Kuasar Task Service 进行通信。当 containerd 请求创建、启动或删除容器或进程时,KuasarServer
Kuasar 运行时的 Containerd 配置
# /etc/containerd/config.toml
# ... other containerd configurations ...
[plugins."io.containerd.grpc.v1.cri"]
# ... other CRI plugin configurations ...
disable_apparmor = true # Important: AppArmor is not supported, must be true
[plugins."io.containerd.grpc.v1.cri".containerd]
# ... other containerd configurations within CRI plugin ...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kuasar-vmm]
runtime_type = "io.containerd.kuasar-vmm.v2"
sandbox_mode = "shim"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kuasar-wasm]
runtime_type = "io.containerd.kuasar-wasm.v2"
sandbox_mode = "shim"
# ... rest of the config.toml ...
将 Kuasar 与 containerd 集成需要对 containerd 配置文件进行特定修改,该文件通常位于 /etc/containerd/config.toml 。这些修改定义了 containerd 如何与 Kuasar 的各种沙箱运行时进行交互。Kuasar shim 充当 CRI runtime V2 backend 负责协调这种通信,详情请参阅 “容器运行时集成”部分 。
对于 kuasar-vmm (MicroVM)和 kuasar-wasm (WebAssembly)运行时,需要配置 containerd runtime_type 和 sandbox_mode 设置。对于 kuasar-vmm ,需要将 runtime_type 设置为 “io.containerd.kuasar-vmm.v2” , sandbox_mode 设置为 “shim” 。类似地,对于 kuasar-wasm , runtime_type 设置为 “io.containerd.kuasar-wasm.v2” , sandbox_mode 也相同。此配置的示例可在 docs/shim/README.md 中找到。
除了这些运行时特定的设置之外, containerd 中的 AppArmor 功能不受 Kuasar 支持,因此需要配置项 disable_apparmor = true 。此外,要启用 containerd 的 Sandbox API ,必须使用环境变量 ENABLE_CRI_SANDBOXES=1 启动 containerd 。此环境变量对于 containerd 正确使用 sandbox_mode = “shim” 设置并将沙箱管理委托给 Kuasar 至关重要。
安装脚本(例如 scripts/install/build-and-install-kuasar-vmm.sh 和 scripts/install/install-kuasar-vmm-x86.sh )会自动将系统中的 containerd 二进制文件替换为 Kuasar 兼容版本,并将 Kuasar 特有的 config.toml 文件复制到 /etc/containerd/config.toml ,其中包含必要的配置。另一方面, uninstall-kuasar-vmm.sh 脚本可以根据需要删除这些配置以及 Kuasar 特有的 containerd ,具体说明请参见 scripts/install/README.md 。
1.3.3 - MicroVM 沙箱
https://codewiki.google/github.com/kuasar-io/kuasar#microvm-sandbox-vmm
Kuasar 的 MicroVM (VMM) 沙箱实现利用虚拟机技术,为容器工作负载提供了一个强大且隔离的环境。这项功能是 Kuasar 多沙箱方法的核心,它在提供强大隔离保障的同时,还能保持性能。VMM 沙箱为每个沙箱编排一个虚拟机,抽象化了复杂的设备管理、cgroup 控制、网络和存储配置。这种抽象化使得容器能够在专用的虚拟机中运行,从而确保它们与其他容器和宿主机系统完全隔离。
VMM 沙箱环境的核心由几个关键组件构成。 vmm-sandboxer 组件负责协调虚拟机的生命周期,包括启动、停止和管理这些 microvm 的资源。在每个客户虚拟机内部,一个名为 vmm-task 轻量级进程以进程 ID 1 运行。该 vmm-task 负责管理客户虚拟机内部的容器和进程生命周期,处理资源分配、网络配置和异步 I/O 操作。主机与客户虚拟机的 vmm-task 之间的通信主要依赖于基于 vsock ttrpc ,从而实现高效的进程间通信,而无需将客户虚拟机的网络暴露给主机。
为了支持各种虚拟机管理程序,例如 Cloud Hypervisor、QEMU 和 StratoVirt,Kuasar 的 VMM 沙箱提供了灵活的集成机制。这包括针对特定虚拟机管理程序的客户端 API 和生命周期管理。该系统还支持针对这些不同的 VMM 和 Kuasar 安全容器对 Linux 内核镜像进行广泛的定制。这种定制(详见“微型虚拟机的 Linux 内核定制” 小节)通常侧重于优化内核以实现最小的内存占用,并根据具体用例将其分为 micro-kernel 或 mini-kernel 。
创建客户操作系统环境涉及多个构建过程。这包括构建客户操作系统根文件系统和镜像、编译 vmm-task 和 runc 二进制文件,以及配置 NVDIMM/DAX 头文件以优化性能。这些过程由脚本协调,以确保客户环境为容器执行做好充分准备。
VMM 沙箱利用过程宏简化了从 Rust 结构体生成命令行参数的过程,从而增强了可配置性和可维护性。这些宏将结构化的 Rust 数据转换为结构化的参数对象或原始命令行参数字符串,方便对虚拟机管理程序和客户机环境进行动态配置。更多信息,请参阅 “使用过程宏派生命令行参数”。
总的来说,Kuasar 的 VMM 沙箱为安全隔离的容器执行提供了一个强大而灵活的解决方案,它通过其 shim proxy 架构与现有的容器运行时(如 containerd 紧密集成,如容器运行时集成中所述。
VMM 编排和 Hypervisor 集成
Kuasar 通过其核心组件 KuasarSandboxer 和 KuasarSandbox ,协调虚拟机 (VM) 沙箱环境,抽象化设备管理、cgroup 控制、网络和存储。该架构支持与各种 Hypervisor(例如 Cloud Hypervisor、QEMU 和 StratoVirt)集成,每种管理程序都由特定的客户端 API 和生命周期管理提供支持。
定义在 vmm/sandbox/src/sandbox.rs 中的 KuasarSandboxer 和 KuasarSandbox 结构体分别实现了 Sandboxer 和 Sandbox 特性,用于管理 KuasarSandbox 实例、其虚拟机和容器的集合。KuasarSandboxer 负责整个沙箱的创建、启动、停止、删除和恢复。 KuasarSandbox KuasarSandboxer 一个基于虚拟机的沙箱,负责管理其 vm 、容器、网络配置以及与 SandboxServiceClient 通信。这包括诸如持久化和恢复沙箱状态、初始化 ttrpc 连接、在虚拟机内设置沙箱以及同步时钟等操作。
不同的虚拟机管理程序实现,包括 Cloud Hypervisor( vmm/sandbox/src/cloud_hypervisor 中的 CloudHypervisorVM 、 CloudHypervisorVMConfig 和 ChClient )、 QemuVM ( vmm/sandbox/src/qemu 中的 QemuVMConfig 、 StratoVirtVM 和 QmpClient )以及 StratoVirt( vmm/sandbox/src/stratovirt 中的 StratoVirtVM、 StratoVirtVMConfig 和 QmpClient ),提供了特定的 VM 和配置结构。这些实现定义了用于创建虚拟机实例 Hooks VMFactory 接口,以及用于启动、停止、挂载、分离和健康检查等操作的 VM 接口。Hooks 特性允许在虚拟机生命周期中注入自定义逻辑,例如 pre_start 和 post_start 操作,而 Recoverable 特性则允许在重启后恢复虚拟机状态。
设备管理由通用的 Device 和 Bus 特性抽象化,这些特性定义在 vmm/sandbox/src/device.rs 文件中,块设备、网络设备和控制台的具体实现则位于相应的虚拟机管理程序目录中。例如, vmm/sandbox/src/cloud_hypervisor/devices 管理 cloud_hypervisor 的设备。类似地,资源隔离的 cgroup 控制由 vmm/sandbox/src/cgroup.rs 处理,该文件提供了创建分层 cgroup、应用资源限制和分配进程的功能。网络配置(包括 NetworkInterface 和 IP 地址管理)在 vmm/sandbox/src/network 目录中进行管理,而存储连接则由 vmm/sandbox/src/storage 进行管理。
这些 VMM 沙箱的命令行参数源自 Rust 结构体,并使用了诸如 CmdLineParams 和 CmdLineParamSet 之类的过程宏,详情请参阅“使用过程宏派生命令行参数” 一文,从而能够动态生成 cloud-hypervisor 和 virtiofsd 的参数。每个 VMM 后端的 KuasarSandboxer 入口点位于 vmm/sandbox/src/bin 目录下,负责协调参数解析、配置加载(例如, vmm/sandbox/src/config.rs 中的 Config::load_config )、跟踪、信号处理和状态恢复。
客户端与沙箱服务的通信由位于 vmm/sandbox/src/client.rs 中的 SandboxServiceClient 管理,它支持 ttrpc 连接,并支持多种套接字类型(Unix、VSock、HVSock),用于执行诸如健康检查、沙箱设置和时钟同步等操作。关于 ttrpc 协议和代码生成等整体架构,包括如何从 protobuf 定义生成 Rust 代码,在 “TTRPC 协议和代码生成”一节中有更详细的阐述。
Guest OS 镜像和根文件系统生成
在 Kuasar 中构建客户操作系统根文件系统和镜像的过程涉及多个精心编排的步骤,旨在为各种虚拟机监控器 (VMM) 创建定制环境。主要的编排工作由 vmm/scripts/image/build.sh 脚本负责,该脚本管理根文件系统的创建,并可选择性地生成 initrd 或完整的可引导镜像。此脚本支持不同的容器运行时环境,包括 containerd 、 docker 和 isulad ,以便在容器化环境中执行根文件系统构建过程。
为了构建完整的与 Kata Containers 兼容的根文件系统镜像,需要使用 vmm/scripts/image/build_image.sh 中的脚本。该脚本会验证根文件系统,计算最佳磁盘大小,使用 qemu-img 创建原始磁盘镜像,并使用 parted 对其进行分区。然后,它会格式化根分区(支持 ext4 或 xfs ),复制根文件系统的内容,并在启用 AGENT_INIT 时优化 systemd 组件以减小镜像大小。一个值得注意的特性是可以使用 nsdax 工具配置 NVDIMM/DAX 标头,该工具会插入特定的元数据以启用支持 pmem 的 NVDIMM 设备功能。
基于 CentOS 的根文件系统使用 vmm/scripts/image/centos/build_rootfs.sh 中的脚本构建。此过程包括构建 Kuasar 的 vmm-task 二进制文件、安装 Go 运行时环境、编译 runc 二进制文件,然后将这些组件以及必要的 glibc 库和列表中指定的其他 RPM 包填充到一个临时根文件系统目录中。许多常用的构建工具(例如用于构建 vmm-task 和 runc 工具)集中在 vmm/scripts/image/common.sh 中,从而提高了模块化程度,并允许在不同根文件系统构建中重复使用。Rust 工具链( vmm-task 的依赖项)的安装由 vmm/scripts/image/install_rust.sh 处理,该脚本确保安装 rustup 并添加用于交叉编译的 unknown-linux-musl 目标。
nsdax 工具(实现于 vmm/scripts/image/nsdax.gpl.c )对于配置 NVDIMM/DAX 头部至关重要。该 C 工具会将 PFN(页帧号)元数据块嵌入到 NVDIMM 镜像文件中。该元数据块基于 Linux 内核 NVDIMM 驱动程序,包含数据偏移和对齐等信息,使内核能够正确解析 NVDIMM 区域。该工具的 main 功能是解析命令行参数,初始化 nd_pfn_sb 结构,使用 nd_fletcher64 和 nd_sb_checksum 计算其校验和,并将该结构写入镜像中的特定偏移量 ( SZ_4K )。这样就实现了双主引导记录 (MBR) 设置,支持 DAX 的系统可以读取第二个 MBR,而其他系统则读取第一个 MBR。
针对 microvm 的 Linux 内核定制
Kuasar 项目包含一个专用框架,用于构建和定制适用于各种虚拟机监控器 (VMM) 和安全容器的 Linux 内核镜像。该流程强调一种“添加式”定制方法,旨在最大限度地减少内存占用和冷启动时间。与从完整的内核配置开始并移除功能不同,该方法选择性地添加必要的功能,从而可以精确控制内核的资源消耗和性能。
内核定制框架主要在 vmm/scripts/kernel 目录下管理,支持多种虚拟机管理程序 (VMM),包括 Cloud Hypervisor、QEMU 和 StratoVirt,以及 Kuasar 安全容器。 vmm/scripts/kernel/build-kernel/build-kernel.sh 脚本负责协调此过程,根据目标架构和内核类型动态选择配置片段。它使用内核构建系统工具将这些片段合并,从而在编译前生成最终的 .config 文件。
支持两种主要的定制内核类型:
-
micro-kernel :专为无服务器和轻量级虚拟机设计,这些内核优先考虑最小的内存开销和低延迟,通常采用 MMIO 总线结构。
-
mini-kernel :这些内核提供更复杂应用程序所需的高级功能,例如 ACPI、SCSI、NFS 和对内核模块的支持,通常使用 PCI 总线结构。
kernel 目录中的特定构建脚本处理每个虚拟机管理程序 (VMM) 的细微差别。例如, vmm/scripts/kernel/cloud_hypervisor/build.sh 专门用于在 x86-64 上为 Cloud Hypervisor 构建 vmlinux.bin ,而 vmm/scripts/kernel/qemu/build.sh 则专注于为 QEMU 生成 bzImage ,并启用 BLK_DEV_INITRD 和 VIRTIO 驱动程序等关键选项。类似地, vmm/scripts/kernel/stratovirt/build.sh 构建专为 openEuler 和 StratoVirt 定制的 aarch64 vmlinux.bin 镜像。
“附加”定制方法的设计选择确保仅包含对 Kuasar VMM 沙箱至关重要的功能,从而缩小攻击面,增强安全态势,并提升性能。有关该方法和性能影响的更多详细信息,请参阅 vmm/scripts/kernel/build-kernel/how-to-tailor-linux-kernel-for-kuasar-security-container.md 。
VMM 任务生命周期和运行时管理
vmm-task 组件负责协调客户虚拟机 (VM) 环境中容器和进程的生命周期。它在客户虚拟机内部以进程 ID 1 运行,管理初始化、资源分配、网络和异步 I/O。该系统利用 ttrpc 进行进程间通信,并利用 tokio 实现并发,从而能够高效地管理容器工作负载。
vmm-task 服务的主要入口点位于 vmm/task/src/main.rs 。该组件初始化虚拟机环境,设置必要的文件系统和内核参数。它还配置一个 ttrpc 服务器,以公开用于管理任务、沙箱和流式传输的服务,从而允许外部组件与虚拟机的内部进程交互。vmm vmm-task 还处理操作系统信号,包括回收子进程和管理优雅关机。
vmm-task 的配置参数由 vmm/task/src/config.rs 中的 TaskConfig 结构管理。该配置通过解析 /proc/cmdline 中的内核命令行参数动态确定,从而允许在运行时进行灵活调整,而无需依赖外部配置文件。
vmm-task 中的容器和进程管理由 shim 层负责,该层在 vmm/task/src/container.rs 中实现。此层充当 containerd 和符合 OCI 标准的运行时(例如 runc 之间的中介。它负责创建容器、解析 OCI Spec 、设置存储以及管理 stdio 重定向。该组件区分初始容器进程和后续 exec 进程,从而提供不同的生命周期管理。一个值得注意的设计是 ShimExecutor ,这是一个自定义的 spawner,它与 containerd-shim 监控系统集成,可以精确地跟踪进程生命周期。错误报告机制完善,可以从 runc 日志文件中提取详细信息。vmm vmm-task 还与 SandboxResources 集成,以管理容器存储生命周期。
沙箱的资源管理集中在 vmm/task/src/sandbox.rs 中的 SandboxResources 内。该组件负责管理存储卷,包括添加、延迟和垃圾回收。它与 vmm/task/src/device.rs 中的 DeviceMonitor 交互 DeviceMonitor 以跟踪和管理块设备和 SCSI 设备。DeviceMonitor 监听内核 uevent,并允许其他组件订阅设备相关事件,从而确保系统能够感知可用硬件。此外, vmm/task/src/sandbox.rs 还负责设置 Linux 命名空间(IPC、UTS、PID)并配置 sysctl 参数以维护沙箱的隔离性。vmm vmm/task/src/mount.rs 中的 get_cgroup_mounts 函数生成必要的 cgroup 挂载配置,支持 v1 和 v2 层次结构。
网络配置由位于 vmm/task/src/netlink.rs Handle 结构处理。该组件提供了一个基于 rtnetlink 高级 API,用于管理客户虚拟机内的网络接口、IP 地址和路由表,通常供代理服务使用。这包括启用环回、更新接口、添加和删除 IP 地址以及管理路由等操作,所有这些操作都使用 protobuf 定义的结构,以实现无缝的 RPC 集成。
I/O 和流管理对于容器功能至关重要,并在 vmm/task/src/io.rs 文件中实现。该文件定义了 ProcessIO 及相关函数,用于管理容器进程的 stdin 、 stdout 和 stderr ,支持多种机制,例如 FIFO、控制台套接字、直接流和 vsock 。它还处理控制台连接,提供用于数据复制的异步函数,并包含一个符合 AsyncRead 和 AsyncWrite 特性的 vsock 流的 VsockIo 实现。vmm vmm/task/src/streaming.rs 中的 Streaming 服务通过 ttrpc 实现流功能,管理标准流的 I/O 通道。此外, vmm/task/src/debug.rs 提供了通过 VSOCK 建立调试控制台的功能,为虚拟机或容器提供 shell 接口。
TTRPC 协议和代码生成
Kuasar 虚拟机监控器 (VMM) 利用 ttrpc 进行进程间通信,而 ttrpc 依赖于从 protobuf 定义生成 Rust 代码。此代码生成过程由 vmm/common/build.rs 构建脚本管理,实现了不同 VMM 组件之间无缝的数据交换和远程过程调用。
vmm/common/build.rs 脚本利用 ttrpc-codegen crate 将 .proto 文件(例如 sandbox.proto 、 events.proto 和 fieldpath.proto )转换为 Rust 源代码。生成的代码为 ttrpc 协议提供了必要的客户端和服务端实现,确保类型安全且高效的通信。例如, vmm/common/src/api/mod.rs 中的 sandbox_ttrpc 和 streaming_ttrpc 模块分别提供了沙箱管理和数据流服务的特定 ttrpc 绑定。
为了维护代码质量并抑制自动生成文件中不必要的警告,构建脚本会进行一些生成后修改。它会移除 #![allow(box_pointers)] 代码检查,该检查用于解决与特定 Rust 特性的兼容性问题,并将 #![allow(clippy::all)] 插入到生成的 _ttrpc.rs 文件中。这确保了自动生成的代码中可能出现的 clippy 警告被抑制,从而保持代码库的整洁,使其专注于开发者编写的逻辑。这使得项目能够专注于生成的 API 组件的语义正确性,而不会被那些并非由开发者直接维护的代码的风格检查所分散注意力。
使用过程宏推导命令行参数
Kuasar 利用过程宏从 Rust 结构体生成命令行参数,简化了定义和解析各种组件参数的过程。这种方法支持两种主要的生成方式:创建结构化的 Param 对象和生成原始命令行参数字符串。这些宏定义在 vmm/sandbox/derive/src/lib.rs 文件中。
CmdLineParams 宏为 crate::param::ToParams trait 生成一个实现,产生一个 crate::param::Param 对象向量。每个 Param 对象代表一个结构化参数,包含一个名称和一个 Property 对象列表。这使得命令行参数能够以详细且有序的方式表示,其中参数中的每个属性都可以具有特定的配置,例如 param 、 key 、 predicate 、 generator 、 ignore_key 和 ignore 属性。这些属性支持对属性生成进行动态控制,允许基于 Rust 表达式有条件地包含或转换值。
相反, CmdLineParamSet 宏会为 crate::param::ToCmdLineParams trait 生成一个实现,该实现会输出一个表示原始命令行参数的 String 向量。此宏处理结构体字段,并使用带有 key 和 ignore 子属性的 param 属性来自定义命令行键或排除字段。它按类型(例如布尔值、原始类型、 Vec 或 Option )对字段进行分类,并将参数生成委托给专门的 crate::param 类型。这种方法通过抽象将 Rust 数据结构转换为可执行参数的过程,简化了命令行接口的创建。
这两个宏 convert_case 利用 syn 和 quote crate 来解析 Rust 语法树和生成新的 Rust 代码。convert_case crate 用于将标识符转换为 kebab-case 格式,以确保生成的命令行参数格式一致。
1.4 - Kuasar资料收集
官方资料
官方网站: https://kuasar.io/
官方文档:https://kuasar.io/docs/
官方博客:https://kuasar.io/blog/
代码仓库: https://github.com/kuasar-io/kuasar
AI 工具
code wiki
https://codewiki.google/github.com/kuasar-io/kuasar
AI 推荐的代码阅读工具
问: 我想系统的学习一个开源项目的代码,理解他的功能,流程,设计,以及实现细节,请问业界有什么比较好的AI工具可以帮助我? 答: gemini 的答复如下。可以参考
这是一个非常好的问题。在 AI 时代,阅读和理解开源代码的效率已经有了质的飞跃。过去我们可能需要几天时间通过打断点、画图来理解一个模块,现在利用 AI 工具可以将这个过程缩短到几小时甚至几十分钟。
要系统地学习一个开源项目(功能 -> 流程 -> 设计 -> 细节),单纯靠“对话”是不够的,你需要的是具有“全代码库上下文(Global Codebase Context)”意识的工具。
以下是目前业界公认最高效的 AI 辅助读码工具方案,按推荐程度排序:
第一梯队:全库感知 IDE (当前最强方案)
这一类工具直接集成了编辑器,并对整个项目进行了索引(Indexing)。这意味着它们不仅仅是看你当前打开的文件,而是“读过”了整个项目。
1. Cursor (强力推荐)
目前业界公认体验最好的 AI 代码编辑器(基于 VS Code 修改)。
- 杀手级功能 -
@Codebase:在对话框输入@Codebase,然后问“这个项目的鉴权流程是怎样的?”,它会检索整个项目,找到相关文件,并总结给你。 - 引用跳转与解释:选中一段复杂的代码,按
Cmd+L,它不仅解释这段代码,还能分析它调用了哪里的函数,以及被哪里调用。 - 文档索引:你可以把该开源项目的官方文档链接加进去(
@Docs),让它结合文档和代码给你解释设计思路。
2. Windsurf (by Codeium)
Cursor 的强力竞争对手,最近非常火。
- Flow 模式:它有一种“Cascade”能力,能够非常深度地感知上下文。当你问它一个功能时,它会主动打开相关的文件,甚至在终端运行命令来辅助理解。它的“代码感知力”在某些复杂场景下甚至优于 Cursor。
第二梯队:代码库搜索引擎 & 问答系统
如果你不想换 IDE,或者项目特别巨大(比如 Linux 内核、Kubernetes 这种 GB 级别的代码),IDE 的本地索引可能会卡死,这时需要云端索引工具。
1. Sourcegraph Cody
Sourcegraph 本身就是做代码搜索起家的,Cody 是他们的 AI 插件。
- 核心优势:企业级/超大项目支持。它的 Graph Context 技术非常精准。对于复杂的开源项目,你可以直接在 VS Code 插件里问:“User 类在数据库中是如何定义的?”,它能精准定位到 Schema 定义文件。
- Web 界面:你甚至不需要下载代码,直接在 Sourcegraph 网页版上加载 GitHub 仓库链接,就可以开始对项目提问。
2. Greptile
这是一个专门为“理解代码库”设计的 API 和工具。
- 核心场景:它专门针对“Onboarding(入职/上手)”场景优化。你可以把 GitHub 仓库发给它,它会像一个资深架构师一样,回答你关于架构、依赖关系的问题。
第三梯队:可视化与设计辅助 (理解宏观架构)
理解代码不仅是看字,更要看图。
1. AI 生成 Mermaid 流程图
结合 Claude 3.5 Sonnet (目前逻辑最强的模型) 或 ChatGPT-4o。
- 用法:复制核心业务逻辑代码(或利用 Cursor 选中代码),提示词:
请分析这段代码的执行流程,并为我生成一个 Mermaid Sequence Diagram(时序图),展示各个模块的交互。 - 效果:将生成的代码贴到 Notion 或 Mermaid Live Editor 中,你就能立刻得到一张清晰的时序图。这对于理解“流程”至关重要。
系统化学习路径建议 (配合 AI 工具)
有了工具,还需要正确的方法。建议按照以下 “五步法” 进行:
第一步:宏观认知 (Claude/GPT-4 + Readme)
- 动作:把项目的
README.md和CONTRIBUTING.md发给 AI。 - Prompt:
我是这个项目的新手,请总结这个项目的核心功能解决了什么问题?它的核心技术栈是什么?主要的架构模式(MVC, Microservices等)是什么?
第二步:寻找入口 (Cursor/Windsurf)
- 动作:寻找程序的启动点(如
main.go,index.ts,Application.java)。 - Prompt (@Codebase):
请帮我找到这个项目的入口文件,并分析程序启动时主要初始化了哪些服务或组件?
第三步:追踪核心链路 (关键步骤)
- 动作:选择一个最具代表性的功能(比如电商项目的“下单”,IM项目的“发送消息”)。
- Prompt (@Codebase):
请带我追踪“用户登录”这一功能的完整代码链路。从 HTTP 收到请求开始,经过了哪些 Controller、Service,直到数据库查询。请列出涉及的关键文件。 - 可视化:让 AI 把这个链路生成 时序图。
第四步:理解实现细节与设计模式
- 动作:打开核心类或复杂函数。
- Prompt:
这段代码使用了什么设计模式?(例如:这里用了工厂模式还是策略模式?)为什么要这样设计?如果不这样写会有什么坏处? - 技巧:这步能帮你学到“设计”,而不仅仅是“实现”。
第五步:验证理解 (生成测试)
- 动作:这是检验你是否真的读懂了的大招。
- Prompt:
我想验证我对这个 calculatePrice 函数的理解,请帮我为它写一个单元测试,覆盖主要的一个边缘情况。 - 逻辑:如果你能运行并通过 AI 写的测试,或者你能指出 AI 写的测试哪里不对,说明你彻底懂了。
总结推荐
- 最推荐的组合:Cursor (编辑器) + Claude 3.5 Sonnet (模型选择)。
- 理由:Cursor 的
@Codebase索引能力配合 Claude 目前地表最强的代码逻辑能力,是目前读源码的“版本答案”。
- 理由:Cursor 的
- 辅助手段:遇到复杂的交互逻辑,立刻让 AI 画 Mermaid 图。
你可以找一个你感兴趣的开源项目(例如一个小型的 Web 框架或工具库),下载 Cursor 试一下这套流程,效率会有惊人的提升。
2 - 快速开始
2.1 - 安装
https://kuasar.io/docs/developer/build/
信息:
- 操作系统: linux mint 22
- 内核: 6.8
cloud hypervisor
MicroVM:要启动基于 MicroVM 的沙盒,必须在主机上安装虚拟机管理程序。
基于 cloud hypervisor 做验证, 安装文档:
https://github.com/cloud-hypervisor/cloud-hypervisor/blob/main/docs/building.md
准备工作:
mkdir -p $HOME/work/soft/cloudhypervisor
export CLOUDH=$HOME/work/soft/cloudhypervisor
cd $CLOUDH
安装依赖包:
sudo apt-get update
sudo apt install git build-essential m4 bison flex uuid-dev qemu-utils musl-tools
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
rustup target add x86_64-unknown-linux-musl
clone 代码并开始构建:
mkdir -p ~/work/code/cloud-hypervisor
cd ~/work/code/cloud-hypervisor
git clone https://github.com/cloud-hypervisor/cloud-hypervisor.git
cd cloud-hypervisor
cargo build --release
sudo setcap cap_net_admin+ep ./target/release/cloud-hypervisor
此时构建好的 cloud-hypervisor 二进制文件在 ./target/release/ 目录下,可以执行命令看一下版本:
$ ./target/release/cloud-hypervisor --version
cloud-hypervisor v48.0-51-g68f9e8244
文件大小 3.9M. 真不大:
ls -lh ./target/release/cloud-hypervisor
-rwxrwxr-x 2 sky sky 3.9M Oct 16 11:17 ./target/release/cloud-hypervisor
安全起见,不用 master 分支构建,改用最新的 release tag,然后采用静态链接:
rm -rf target
git checkout v48.0
cargo build --release --target=x86_64-unknown-linux-musl --all
sudo setcap cap_net_admin+ep ./target/x86_64-unknown-linux-musl/release/cloud-hypervisor
./target/x86_64-unknown-linux-musl/release/cloud-hypervisor --version
cloud-hypervisor v48.0
ls -lh ./target/x86_64-unknown-linux-musl/release/cloud-hypervisor
-rwxrwxr-x 2 sky sky 4.0M Oct 16 15:31 ./target/x86_64-unknown-linux-musl/release/cloud-hypervisor
静态链接也才4M,没大多少.
microVM
3 - 组件
3.1 - 概述
所有组件
代码分析
kuasar 代码仓库中共有如下 11 个 Cargo.toml:
-
Cargo.toml
-
shim/Cargo.toml
-
vmm/task/Cargo.toml
-
runc/Cargo.toml
-
quark/Cargo.toml
-
wasm/Cargo.toml
-
vmm/sandbox/src/bin
-
vmm/sandbox/src/bin/qemu/main.rs
-
runc/src/main.rs
-
quark/src/main.rs
-
wasm/src/main.rs
通过对上述所有 Cargo.toml 文件的分析,kuasar项目总共会打包出以下二进制文件。
二进制文件总览
kuasar项目总共会打包出8个主要的二进制文件,分为以下几类:
1. Shim 二进制文件 (2个)
- containerd-shim-kuasar-vmm-v2
- 功能:VMM sandboxer的containerd shim
- main入口:
shim/src/bin/containerd-shim-kuasar-vmm-v2.rs
- containerd-shim-kuasar-wasm-v2
- 功能:WASM sandboxer的containerd shim
- main入口:
shim/src/bin/containerd-shim-kuasar-wasm-v2.rs
2. Sandboxer 二进制文件 (4个)
- quark-sandboxer
- 功能:App-Kernel沙箱运行时
- main入口:
quark/src/main.rs
- runc-sandboxer
- 功能:传统runc沙箱运行时的包装器
- main入口:
runc/src/main.rs
- wasm-sandboxer
- 功能:WebAssembly沙箱运行时(支持WasmEdge和Wasmtime)
- main入口:
wasm/src/main.rs
- vmm-task
- 功能:VMM任务服务器(在虚拟机内部运行)
- main入口:
vmm/task/src/main.rs
3. VMM Hypervisor 二进制文件 (3个)
这些都在vmm/sandbox模块中定义:
- qemu
- 功能:基于QEMU的虚拟机监控器
- main入口:
vmm/sandbox/src/bin/qemu/main.rs
- cloud_hypervisor
- 功能:基于Cloud Hypervisor的虚拟机监控器
- main入口:
vmm/sandbox/src/bin/cloud_hypervisor/main.rs
- stratovirt
- 功能:基于StratoVirt的虚拟机监控器
- main入口:
vmm/sandbox/src/bin/stratovirt/main.rs
4. 测试工具 (1个)
- kuasar-e2e
- 功能:端到端测试工具
- main入口:
tests/e2e/src/main.rs
关于Cargo.toml的说明
并不是所有的Cargo.toml都会打包出二进制文件:
- vmm/common/Cargo.toml: 这是一个库(library)模块,不生成二进制文件,只提供给其他模块使用的共享代码
- vmm/sandbox/derive/Cargo.toml: 这是一个过程宏库,不生成独立的二进制文件
所以总结来说,kuasar项目会生成8个主要的可执行二进制文件,覆盖了从容器运行时到虚拟机监控器的完整技术栈。
cloud hypervisor 相关
相关的二进制文件
如果只考虑启动Cloud Hypervisor的microVM,需要使用到的二进制文件包括:
必需的Kuasar二进制文件
-
Shim二进制文件 containerd-shim-kuasar-vmm-v2
- 功能:作为containerd和VMM sandboxer之间的桥梁
- 位置:
shim/src/bin/containerd-shim-kuasar-vmm-v2.rs - 作用:接收containerd的CRI调用,转发给VMM sandboxer
-
VMM Sandboxer二进制文件 cloud_hypervisor (VMM sandboxer的一个实现)
- 功能:基于Cloud Hypervisor的虚拟机监控器和沙箱管理器
- 位置:
vmm/sandbox/src/bin/cloud_hypervisor/main.rs - 作用:创建和管理Cloud Hypervisor虚拟机实例,处理容器生命周期
-
虚拟机内部任务服务器 vmm-task
- 功能:在虚拟机内部运行的任务服务器
- 位置:
vmm/task/src/main.rs - 作用:在VM内部处理容器的创建、启动、停止等操作
外部依赖的二进制文件
-
Cloud Hypervisor本体
- 这是外部的Cloud Hypervisor项目提供的二进制文件
- Kuasar通过调用这个二进制文件来实际启动和管理虚拟机
总结: 最核心的是这4个二进制文件:
containerd-shim-kuasar-vmm-v2(Kuasar提供)cloud_hypervisorVMM sandboxer (Kuasar提供)vmm-task(Kuasar提供)cloud-hypervisor(外部Cloud Hypervisor项目提供)
这是启动Cloud Hypervisor microVM的最小二进制文件集合。其他的sandboxer(如wasm、quark、runc)以及对应的shim在这个场景下都不需要。
典型的工作流程
- containerd 接收到创建Pod/容器的请求
- containerd-shim-kuasar-vmm-v2 被containerd调用
- cloud_hypervisor (VMM sandboxer) 被shim启动
- VMM sandboxer调用外部的 cloud-hypervisor 二进制文件创建虚拟机
- vmm-task 在虚拟机内部启动,处理容器相关操作
sequenceDiagram
participant User as 用户/Kubernetes
participant Containerd as containerd
participant Shim as containerd-shim-kuasar-vmm-v2
participant VMM as cloud_hypervisor (VMM Sandboxer)
participant CH as cloud-hypervisor (外部二进制)
participant VM as Virtual Machine
participant Task as vmm-task (VM内部)
Note over User, Task: Cloud Hypervisor MicroVM 创建流程
%% 1. 创建Pod/容器请求
User->>Containerd: 创建Pod请求 (via CRI)
Note right of User: kubectl/crictl create pod
%% 2. Containerd调用Shim
Containerd->>Shim: 启动 containerd-shim-kuasar-vmm-v2
Note right of Containerd: containerd识别runtime类型<br/>选择kuasar-vmm runtime
%% 3. Shim与VMM Sandboxer通信
Shim->>VMM: 通过Unix Socket连接VMM Sandboxer
Shim->>VMM: 发送CreateSandbox请求
Note right of Shim: 传递容器规格、网络配置等
%% 4. VMM Sandboxer创建虚拟机
VMM->>VMM: 生成Cloud Hypervisor配置
Note right of VMM: 配置CPU、内存、网络、存储等
VMM->>CH: 调用cloud-hypervisor二进制
Note right of VMM: 启动hypervisor进程
CH->>VM: 创建并启动虚拟机
Note right of CH: 初始化VM硬件、加载内核
%% 5. VM内部初始化
VM->>Task: 启动vmm-task服务
Note right of VM: VM启动后自动运行vmm-task
Task->>VMM: 建立VM内外通信连接
Note right of Task: 通过vsock或其他方式
%% 6. 创建容器
VMM->>Task: 发送CreateContainer请求
Note right of VMM: 传递容器镜像、配置等
Task->>Task: 在VM内创建容器
Note right of Task: 设置namespace、挂载、进程等
Task->>VMM: 返回创建成功响应
%% 7. 启动容器
VMM->>Task: 发送StartContainer请求
Task->>Task: 启动容器进程
Task->>VMM: 返回启动成功响应
%% 8. 响应链路返回
VMM->>Shim: 返回Sandbox创建成功
Shim->>Containerd: 返回成功响应
Containerd->>User: Pod/容器创建完成
%% 9. 运行时管理(可选)
Note over Shim, Task: 运行时操作 (exec, logs, stats等)
User->>Containerd: 执行命令 (kubectl exec)
Containerd->>Shim: 转发exec请求
Shim->>VMM: 发送exec请求
VMM->>Task: 转发到VM内部
Task->>Task: 在容器内执行命令
Task->>VMM: 返回执行结果
VMM->>Shim: 转发结果
Shim->>Containerd: 返回结果
Containerd->>User: 显示命令输出
这个序列图展示了以下关键步骤:
主要阶段
- 请求发起: 用户通过kubectl/crictl发起Pod创建请求
- Shim启动: containerd根据RuntimeClass选择并启动kuasar shim
- Sandbox创建: Shim与VMM Sandboxer通信,请求创建新的沙箱
- VM创建: VMM Sandboxer调用Cloud Hypervisor创建虚拟机
- VM初始化: 虚拟机启动,内部的vmm-task服务开始运行
- 容器管理: 通过VM内外通信在虚拟机内创建和启动容器
- 运行时操作: 支持exec、logs等运行时操作
关键组件职责
- containerd-shim-kuasar-vmm-v2: CRI到Kuasar的适配层
- cloud_hypervisor (VMM Sandboxer): 虚拟机生命周期管理
- cloud-hypervisor: 实际的hypervisor进程
- vmm-task: VM内部的容器管理服务
这个架构实现了容器在轻量级虚拟机中的强隔离运行。
3.2 - 生命周期
仅考虑创建 cloud hypervisor microvm 的场景。
组件生命周期分析
长时间运行的服务组件(守护进程)
-
containerd
- 类型: 外部长期运行的系统服务
- 生命周期: 系统级守护进程,通过systemd管理
- 功能: 容器运行时管理,接收CRI调用
-
VMM Sandboxer (
cloud_hypervisor)- 类型: Kuasar提供的长期运行服务
- 生命周期: 通过systemd服务启动并持续运行
- 服务文件:
vmm/service/kuasar-vmm.service - 功能:
- 监听Unix Socket等待沙箱创建请求
- 管理多个虚拟机实例的生命周期
- 与containerd shim通信
-
cloud-hypervisor进程
- 类型: 外部hypervisor守护进程
- 生命周期: 每个VM对应一个进程,VM存在期间持续运行
- 功能: 实际的虚拟机监控和硬件模拟
-
vmm-task (VM内部)
- 类型: VM内部的任务服务器
- 生命周期: 随VM启动而启动,VM存在期间持续运行
- 功能: 在VM内部处理容器操作请求
短时间运行的临时组件
-
containerd-shim-kuasar-vmm-v2
- 类型: 临时进程
- 生命周期 :
- 由containerd为每个Pod启动
- Pod删除时退出
- 功能: 作为containerd和VMM sandboxer之间的桥梁
timeline
title 组件生命周期时序
section 系统启动
系统启动 : containerd启动
: VMM Sandboxer启动 (通过systemd)
section Pod创建请求
请求到达 : containerd接收创建请求
Shim启动 : containerd启动shim进程
VM创建 : VMM Sandboxer启动cloud-hypervisor
: VM启动,vmm-task启动
section Pod运行期间
稳定运行 : containerd (持续运行)
: VMM Sandboxer (持续运行)
: cloud-hypervisor (持续运行)
: vmm-task (持续运行)
: containerd-shim (持续运行)
section Pod删除
清理阶段 : containerd-shim退出
: VM被销毁
: cloud-hypervisor进程退出
: vmm-task随VM退出
Cloud Hypervisor 场景
以连续创建并删除3个Cloud Hypervisor microVM为例,各个组件的参与流程和生命周期:
gantt
title Kuasar Cloud Hypervisor - 3个Pod的组件生命周期
dateFormat YYYY-MM-DD
axisFormat %m-%d
section 持久服务 (长期运行)
containerd daemon :done, containerd, 2024-01-01, 2024-01-05
vmm-sandboxer service :done, vmmsandboxer, 2024-01-01, 2024-01-05
virtiofsd daemon :done, virtiofsd, 2024-01-01, 2024-01-05
section Pod-1 (临时组件)
Cloud Hypervisor-1 :active, chv1, 2024-01-01, 2024-01-02
vmm-task-1 (Guest) :active, task1, 2024-01-01, 2024-01-02
Container Process-1 :active, container1, 2024-01-01, 2024-01-02
section Pod-2 (临时组件)
Cloud Hypervisor-2 :active, chv2, 2024-01-02, 2024-01-03
vmm-task-2 (Guest) :active, task2, 2024-01-02, 2024-01-03
Container Process-2 :active, container2, 2024-01-02, 2024-01-03
section Pod-3 (临时组件)
Cloud Hypervisor-3 :active, chv3, 2024-01-03, 2024-01-04
vmm-task-3 (Guest) :active, task3, 2024-01-03, 2024-01-04
Container Process-3 :active, container3, 2024-01-03, 2024-01-04
长时间运行,服务于全部 3 次创建和删除的组件是:
- containerd daemon
- vmm-sandboxer service
- virtiofsd daemon
时间线视图
timeline
title Kuasar Cloud Hypervisor - 连续3个Pod生命周期
section 系统启动
系统初始化 : containerd daemon启动
: vmm-sandboxer service启动
: virtiofsd daemon启动
section Pod-1 创建
MicroVM-1启动 : Cloud Hypervisor-1进程启动
: vmm-task-1 (Guest PID 1)启动
: 容器进程-1运行
section Pod-2 创建
MicroVM-2启动 : Cloud Hypervisor-2进程启动
: vmm-task-2 (Guest PID 1)启动
: 容器进程-2运行
section Pod-3 创建
MicroVM-3启动 : Cloud Hypervisor-3进程启动
: vmm-task-3 (Guest PID 1)启动
: 容器进程-3运行
section 清理阶段
清理Pod-1 : 容器进程-1停止
: Cloud Hypervisor-1退出
: vmm-task-1终止
清理Pod-2 : 容器进程-2停止
: Cloud Hypervisor-2退出
: vmm-task-2终止
清理Pod-3 : 容器进程-3停止
: Cloud Hypervisor-3退出
: vmm-task-3终止
section 持续服务
后台运行 : containerd daemon (持续运行)
: vmm-sandboxer service (持续运行)
: virtiofsd daemon (持续运行)
详细交互流程图
sequenceDiagram
participant User as kubectl/crictl
participant CD as containerd
participant VMS as vmm-sandboxer
participant CHV1 as Cloud Hypervisor-1
participant Task1 as vmm-task-1 (Guest)
participant Runc1 as runc-1 (Guest)
participant CHV2 as Cloud Hypervisor-2
participant Task2 as vmm-task-2 (Guest)
participant CHV3 as Cloud Hypervisor-3
participant Task3 as vmm-task-3 (Guest)
Note over User,Task3: === Pod-1 创建流程 ===
User->>CD: CreateSandbox(pod-1)
CD->>VMS: CreateSandbox API
VMS->>VMS: Factory.create_vm()
VMS->>CHV1: 启动 cloud-hypervisor 进程
activate CHV1
CHV1->>Task1: 启动 vmm-task (PID 1)
activate Task1
Task1->>VMS: vsock连接注册
VMS-->>CD: CreateSandboxResponse
User->>CD: CreateContainer(container-1)
CD->>VMS: CreateContainer API
VMS->>Task1: CreateContainer (via vsock)
Task1->>Runc1: runc create + start
activate Runc1
Task1-->>VMS: Success
VMS-->>CD: Success
Note over User,Task3: === Pod-2 创建流程 ===
User->>CD: CreateSandbox(pod-2)
CD->>VMS: CreateSandbox API
VMS->>CHV2: 启动 cloud-hypervisor 进程
activate CHV2
CHV2->>Task2: 启动 vmm-task (PID 1)
activate Task2
Task2->>VMS: vsock连接注册
VMS-->>CD: CreateSandboxResponse
User->>CD: CreateContainer(container-2)
CD->>VMS: CreateContainer API
VMS->>Task2: CreateContainer (via vsock)
Task2->>Task2: runc create + start
VMS-->>CD: Success
Note over User,Task3: === Pod-3 创建流程 ===
User->>CD: CreateSandbox(pod-3)
CD->>VMS: CreateSandbox API
VMS->>CHV3: 启动 cloud-hypervisor 进程
activate CHV3
CHV3->>Task3: 启动 vmm-task (PID 1)
activate Task3
Task3->>VMS: vsock连接注册
VMS-->>CD: CreateSandboxResponse
Note over User,Task3: === 删除流程 (按创建顺序) ===
User->>CD: StopSandbox(pod-1)
CD->>VMS: StopSandbox API
VMS->>CHV1: SIGTERM/shutdown
CHV1->>Task1: VM shutdown
deactivate Runc1
deactivate Task1
deactivate CHV1
User->>CD: StopSandbox(pod-2)
CD->>VMS: StopSandbox API
VMS->>CHV2: SIGTERM/shutdown
deactivate Task2
deactivate CHV2
User->>CD: StopSandbox(pod-3)
CD->>VMS: StopSandbox API
VMS->>CHV3: SIGTERM/shutdown
deactivate Task3
deactivate CHV3
架构组件图:
graph TB
subgraph "Host System (持久层)"
CD[containerd daemon<br/>📍 长期运行]
VMS[vmm-sandboxer service<br/>📍 长期运行<br/>Unix Socket:/run/vmm-sandboxer.sock]
VFS[virtiofsd<br/>📍 长期运行]
Shim[containerd-shim-kuasar-vmm-v2<br/>📍 可选组件]
end
subgraph "Pod-1 (临时)"
CHV1[Cloud Hypervisor-1<br/>⏱️ 临时进程]
subgraph "Guest VM-1"
Task1[vmm-task-1<br/>⏱️ Guest PID 1]
Runc1[runc-1<br/>⏱️ 容器管理器]
Proc1[container-process-1<br/>⏱️ 应用进程]
end
end
subgraph "Pod-2 (临时)"
CHV2[Cloud Hypervisor-2<br/>⏱️ 临时进程]
subgraph "Guest VM-2"
Task2[vmm-task-2<br/>⏱️ Guest PID 1]
Runc2[runc-2<br/>⏱️ 容器管理器]
Proc2[container-process-2<br/>⏱️ 应用进程]
end
end
subgraph "Pod-3 (临时)"
CHV3[Cloud Hypervisor-3<br/>⏱️ 临时进程]
subgraph "Guest VM-3"
Task3[vmm-task-3<br/>⏱️ Guest PID 1]
Runc3[runc-3<br/>⏱️ 容器管理器]
Proc3[container-process-3<br/>⏱️ 应用进程]
end
end
CD --> VMS
VMS --> CHV1
VMS --> CHV2
VMS --> CHV3
CHV1 --> Task1
Task1 --> Runc1
Runc1 --> Proc1
CHV2 --> Task2
Task2 --> Runc2
Runc2 --> Proc2
CHV3 --> Task3
Task3 --> Runc3
Runc3 --> Proc3
VMS -.vsock.-> Task1
VMS -.vsock.-> Task2
VMS -.vsock.-> Task3
VFS -.virtio-fs.-> CHV1
VFS -.virtio-fs.-> CHV2
VFS -.virtio-fs.-> CHV3
style CD fill:#e1f5fe
style VMS fill:#e1f5fe
style VFS fill:#e1f5fe
style CHV1 fill:#fff3e0
style CHV2 fill:#fff3e0
style CHV3 fill:#fff3e0
style Task1 fill:#f3e5f5
style Task2 fill:#f3e5f5
style Task3 fill:#f3e5f5
进程生命周期状态图
stateDiagram-v2
[*] --> SystemInit: 系统启动
SystemInit --> ContainerdRunning: 启动containerd
ContainerdRunning --> VMSandboxerRunning: 启动vmm-sandboxer
VMSandboxerRunning --> VirtioFSRunning: 启动virtiofsd
VirtioFSRunning --> Ready: 持久服务就绪
Ready --> ParallelCreation: 开始并行创建3个Pod
state ParallelCreation {
[*] --> Pod1Creating
[*] --> Pod2Creating
[*] --> Pod3Creating
state Pod1Creating {
[*] --> CHV1Starting: Cloud Hypervisor-1启动
CHV1Starting --> Task1Ready: vmm-task-1初始化
Task1Ready --> Container1Running: 容器-1运行
Container1Running --> Pod1Ready: Pod-1就绪
}
state Pod2Creating {
[*] --> CHV2Starting: Cloud Hypervisor-2启动
CHV2Starting --> Task2Ready: vmm-task-2初始化
Task2Ready --> Container2Running: 容器-2运行
Container2Running --> Pod2Ready: Pod-2就绪
}
state Pod3Creating {
[*] --> CHV3Starting: Cloud Hypervisor-3启动
CHV3Starting --> Task3Ready: vmm-task-3初始化
Task3Ready --> Container3Running: 容器-3运行
Container3Running --> Pod3Ready: Pod-3就绪
}
Pod1Ready --> AllPodsReady
Pod2Ready --> AllPodsReady
Pod3Ready --> AllPodsReady
}
ParallelCreation --> AllPodsRunning: 所有Pod创建完成
AllPodsRunning --> ParallelDeletion: 开始并行删除
state ParallelDeletion {
[*] --> Pod1Deleting
[*] --> Pod2Deleting
[*] --> Pod3Deleting
state Pod1Deleting {
[*] --> Container1Stopping: 停止容器-1
Container1Stopping --> CHV1Shutdown: 关闭Cloud Hypervisor-1
CHV1Shutdown --> Task1Terminated: vmm-task-1终止
Task1Terminated --> Pod1Deleted: Pod-1已删除
}
state Pod2Deleting {
[*] --> Container2Stopping: 停止容器-2
Container2Stopping --> CHV2Shutdown: 关闭Cloud Hypervisor-2
CHV2Shutdown --> Task2Terminated: vmm-task-2终止
Task2Terminated --> Pod2Deleted: Pod-2已删除
}
state Pod3Deleting {
[*] --> Container3Stopping: 停止容器-3
Container3Stopping --> CHV3Shutdown: 关闭Cloud Hypervisor-3
CHV3Shutdown --> Task3Terminated: vmm-task-3终止
Task3Terminated --> Pod3Deleted: Pod-3已删除
}
Pod1Deleted --> AllPodsDeleted
Pod2Deleted --> AllPodsDeleted
Pod3Deleted --> AllPodsDeleted
}
ParallelDeletion --> ServicesContinue: 所有Pod清理完成
ServicesContinue --> Ready: 持久服务继续运行
note right of Ready
持久服务层组件:
- containerd daemon
- vmm-sandboxer service
- virtiofsd daemon
这些组件持续运行
end note
note right of AllPodsRunning
3个Pod并行运行中:
- Pod-1: CHV1 + Task1 + Container1
- Pod-2: CHV2 + Task2 + Container2
- Pod-3: CHV3 + Task3 + Container3
end note
简化版本:
stateDiagram-v2
[*] --> SystemReady: 持久服务启动
state SystemReady {
[*] --> ContainerdRunning
[*] --> VMSandboxerRunning
[*] --> VirtioFSRunning
}
SystemReady --> CreatePods: 开始创建Pod
state CreatePods {
[*] --> CreatingPod1
[*] --> CreatingPod2
[*] --> CreatingPod3
CreatingPod1 --> Pod1Running: CHV1+Task1+Container1
CreatingPod2 --> Pod2Running: CHV2+Task2+Container2
CreatingPod3 --> Pod3Running: CHV3+Task3+Container3
}
CreatePods --> AllRunning: 3个Pod都在运行
AllRunning --> DeletePods: 开始删除Pod
state DeletePods {
[*] --> DeletingPod1
[*] --> DeletingPod2
[*] --> DeletingPod3
DeletingPod1 --> Pod1Deleted: 清理CHV1+Task1+Container1
DeletingPod2 --> Pod2Deleted: 清理CHV2+Task2+Container2
DeletingPod3 --> Pod3Deleted: 清理CHV3+Task3+Container3
}
DeletePods --> SystemReady: 持久服务继续运行
资源管理视图
graph TD
subgraph "持久服务层 (长期运行)"
A[containerd daemon]
B[vmm-sandboxer service]
C[virtiofsd daemon]
end
subgraph "Pod-1 (临时组件)"
D1[Cloud Hypervisor-1]
E1[vmm-task-1]
F1[runc + container-1]
end
subgraph "Pod-2 (临时组件)"
D2[Cloud Hypervisor-2]
E2[vmm-task-2]
F2[runc + container-2]
end
subgraph "Pod-3 (临时组件)"
D3[Cloud Hypervisor-3]
E3[vmm-task-3]
F3[runc + container-3]
end
A --> B
B -.管理.-> D1
B -.管理.-> D2
B -.管理.-> D3
D1 --> E1
E1 --> F1
D2 --> E2
E2 --> F2
D3 --> E3
E3 --> F3
C -.virtio-fs.-> D1
C -.virtio-fs.-> D2
C -.virtio-fs.-> D3
style A fill:#e8f5e8,stroke:#2e7d2e,stroke-width:2px
style B fill:#e8f5e8,stroke:#2e7d2e,stroke-width:2px
style C fill:#e8f5e8,stroke:#2e7d2e,stroke-width:2px
style D1 fill:#ffe8e8,stroke:#d32f2f,stroke-width:2px
style D2 fill:#ffe8e8,stroke:#d32f2f,stroke-width:2px
style D3 fill:#ffe8e8,stroke:#d32f2f,stroke-width:2px
style E1 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style E2 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
style E3 fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
3.3 - shim特殊设计
背景:发现 greptile 在回答时说 shim 是 1:1 模型,但看 kuasar 的介绍又说 kuasar 特意对 shim 进行了优化,采用 1:N 模型。所以深挖了一下。
问: containerd-shim-kuasar-vmm-v2 这个组件,在连续创建 cloud hypervisor 的 microvm 时,是会为每个 micorovm 的创建而启动一个 containerd-shim-kuasar-vmm-v2 实例,还是一直重用一个 containerd-shim-kuasar-vmm-v2 实例?
再问:关于这一点,我看到 kuasar 的介绍中提到:
优化框架:通过移除所有暂停容器并将 shim 进程替换为单个驻留沙盒器进程,Kuasar 进行了优化,带来了 1:N 进程管理模型,其性能优于当前的 1:1 shim v2 进程模型。基准测试结果显示,Kuasar 的沙盒启动速度提升 2 倍,而管理资源开销降低了 99%。更多详情请参考性能。
greptile的回答:
containerd-shim-kuasar-vmm-v2 确实会为每个 microVM 的创建而启动一个新的实例,但所有实例都连接到同一个长期运行的 sandboxer 进程。 这是 Kuasar 实现性能优化的关键架构设计。
Kuasar 的双层架构设计原理
Kuasar 采用了一种巧妙的双层架构,既保持了与 containerd shim v2 API 的完全兼容性,又实现了显著的性能优化:
第一层:Shim 层(1:1 模型)
- 每个 sandbox 仍然有一个独立的 containerd-shim-kuasar-vmm-v2 实例
- 这些 shim 进程变得极其轻量,主要负责:
- 接收 containerd 的 API 调用
- 转发请求给 sandboxer 进程
- 处理 I/O 管道和信号
第二层:Sandboxer 层(1:N 模型)
- 单一的长期运行的 sandboxer 进程(如
kuasar-vmm) - 管理多个 Cloud Hypervisor microVM 实例
- 处理所有重量级操作
整体架构图
graph TD
subgraph "Container Orchestrator Layer"
K8s[Kubernetes]
Containerd[containerd daemon]
end
subgraph "Shim Layer (1:1 Model)"
Shim1["containerd-shim-kuasar-vmm-v2<br/>Instance 1<br/>PID: 1001<br/>轻量级进程"]
Shim2["containerd-shim-kuasar-vmm-v2<br/>Instance 2<br/>PID: 1002<br/>轻量级进程"]
Shim3["containerd-shim-kuasar-vmm-v2<br/>Instance 3<br/>PID: 1003<br/>轻量级进程"]
end
subgraph "Sandboxer Layer (1:N Model)"
VMM["kuasar-vmm<br/>单一驻留进程<br/>PID: 2000<br/>systemd 服务"]
Socket["/run/vmm-sandboxer.sock"]
end
subgraph "Hypervisor Layer"
VM1["Cloud Hypervisor<br/>microVM 1<br/>sandbox-abc123"]
VM2["Cloud Hypervisor<br/>microVM 2<br/>sandbox-def456"]
VM3["Cloud Hypervisor<br/>microVM 3<br/>sandbox-ghi789"]
end
K8s --> Containerd
Containerd --> Shim1
Containerd --> Shim2
Containerd --> Shim3
Shim1 -.->|Unix Socket<br/>ttrpc gRPC| Socket
Shim2 -.->|Unix Socket<br/>ttrpc gRPC| Socket
Shim3 -.->|Unix Socket<br/>ttrpc gRPC| Socket
Socket --> VMM
VMM --> VM1
VMM --> VM2
VMM --> VM3
style Shim1 fill:#e1f5fe,stroke:#01579b,stroke-width:2px
style Shim2 fill:#e1f5fe,stroke:#01579b,stroke-width:2px
style Shim3 fill:#e1f5fe,stroke:#01579b,stroke-width:2px
style VMM fill:#fff3e0,stroke:#e65100,stroke-width:3px
style VM1 fill:#f3e5f5,stroke:#4a148c
style VM2 fill:#f3e5f5,stroke:#4a148c
style VM3 fill:#f3e5f5,stroke:#4a148c
style Socket fill:#e8f5e8,stroke:#2e7d32
进程创建和通信时序图
sequenceDiagram
participant Containerd
participant Shim1 as containerd-shim-kuasar-vmm-v2 #1
participant Shim2 as containerd-shim-kuasar-vmm-v2 #2
participant VMM as kuasar-vmm (驻留进程)
participant CH1 as Cloud Hypervisor #1
participant CH2 as Cloud Hypervisor #2
Note over VMM: kuasar-vmm 作为 systemd 服务<br/>已经在运行,监听 /run/vmm-sandboxer.sock
rect rgb(240, 248, 255)
Note right of Containerd: 创建第一个 sandbox
Containerd->>+Shim1: 启动新的 shim 实例
Shim1->>Shim1: fork() 新进程,绑定到 sandbox ID
Shim1->>+VMM: ttrpc: CreateSandbox(id: "sandbox-abc123")
VMM->>VMM: 在内存中注册新 sandbox
VMM->>+CH1: 启动 Cloud Hypervisor microVM 1
CH1->>CH1: 初始化 VM,分配资源
CH1-->>-VMM: microVM 1 启动完成
VMM-->>-Shim1: CreateSandboxResponse
Shim1-->>-Containerd: 返回成功
end
rect rgb(255, 248, 240)
Note right of Containerd: 并行创建第二个 sandbox
Containerd->>+Shim2: 启动新的 shim 实例
Shim2->>Shim2: fork() 新进程,绑定到不同 sandbox ID
Shim2->>+VMM: ttrpc: CreateSandbox(id: "sandbox-def456")
VMM->>VMM: 复用现有连接和内存结构
VMM->>+CH2: 启动 Cloud Hypervisor microVM 2
CH2->>CH2: 初始化 VM,分配资源
CH2-->>-VMM: microVM 2 启动完成
VMM-->>-Shim2: CreateSandboxResponse
Shim2-->>-Containerd: 返回成功
end
Note over Shim1, VMM: 两个 shim 实例同时连接到<br/>同一个 kuasar-vmm 进程
资源优化对比图
graph LR
subgraph "传统 Shim v2 (1:1 模型) - 资源重复"
direction TB
C1[Container 1] --> S1["Shim 1<br/>重量级<br/>内存: 50MB<br/>CPU: 10%"]
C2[Container 2] --> S2["Shim 2<br/>重量级<br/>内存: 50MB<br/>CPU: 10%"]
C3[Container 3] --> S3["Shim 3<br/>重量级<br/>内存: 50MB<br/>CPU: 10%"]
S1 --> R1["Runtime 1<br/>hypervisor API"]
S2 --> R2["Runtime 2<br/>hypervisor API"]
S3 --> R3["Runtime 3<br/>hypervisor API"]
TotalOld["总资源:<br/>内存: 150MB<br/>CPU: 30%<br/>进程数: 6"]
end
subgraph "Kuasar 优化 (1:1 + 1:N 混合) - 资源共享"
direction TB
C4[Container 1] --> S4["Shim 1<br/>轻量级<br/>内存: 2MB<br/>CPU: 0.1%"]
C5[Container 2] --> S5["Shim 2<br/>轻量级<br/>内存: 2MB<br/>CPU: 0.1%"]
C6[Container 3] --> S6["Shim 3<br/>轻量级<br/>内存: 2MB<br/>CPU: 0.1%"]
S4 --> VMM2["kuasar-vmm<br/>单一重量级进程<br/>内存: 20MB<br/>CPU: 5%"]
S5 --> VMM2
S6 --> VMM2
VMM2 --> V1[microVM 1]
VMM2 --> V2[microVM 2]
VMM2 --> V3[microVM 3]
TotalNew["总资源:<br/>内存: 26MB (节省 83%)<br/>CPU: 5.3% (节省 82%)<br/>进程数: 4 (节省 33%)"]
end
style S1 fill:#ffcdd2,stroke:#c62828
style S2 fill:#ffcdd2,stroke:#c62828
style S3 fill:#ffcdd2,stroke:#c62828
style S4 fill:#e8f5e8,stroke:#2e7d32
style S5 fill:#e8f5e8,stroke:#2e7d32
style S6 fill:#e8f5e8,stroke:#2e7d32
style VMM2 fill:#fff3e0,stroke:#e65100
style TotalOld fill:#ffebee,stroke:#b71c1c
style TotalNew fill:#f1f8e9,stroke:#33691e
代码实现细节
Shim 层的轻量化实现
从 shim/src/service.rs 可以看到,每个 shim 实例的核心职责:
// 每个 shim 实例都有独立的 ID 和数据结构
2impl<Transport> Shim for Service<Transport> {
3 async fn new(_runtime_id: &str, id: &str, _namespace: &str, _config: &mut Config) -> Self {
4 let exit = Arc::new(ExitSignal::default());
5 Self {
6 kuasar_server: Box::new(KuasarServer::new(id, exit).await),
7 }
8 }
9}
10
11// 但所有 shim 实例都连接到同一个 sandboxer 地址
12impl<T: ContainerIoTransport> KuasarServer<T> {
13 pub async fn new(id: &str, exit: Arc<ExitSignal>) -> Self {
14 let channel = Endpoint::from_static("https://www.kuasar.io")
15 .connect_with_connector(service_fn(
16 |_: Uri| UnixStream::connect(T::sandboxer_addr()), // 同一个 socket 地址!
17 ))
18 .await
19 .expect("sandboxer should be running");
20 }
21}
Sandboxer 层的单实例架构
从 vmm/sandbox/src/bin/qemu/main.rs 可以看到,sandboxer 作为单一进程运行:
#[tokio::main]
2async fn main() {
3 // 创建单一的 sandboxer 实例
4 let mut sandboxer: KuasarSandboxer<QemuVMFactory, QemuHooks> = KuasarSandboxer::new(
5 config.sandbox,
6 config.hypervisor.clone(),
7 QemuHooks::new(config.hypervisor),
8 );
9
10 // 在指定地址监听,为所有 shim 提供服务
11 containerd_sandbox::run(
12 "kuasar-vmm-sandboxer-qemu",
13 &args.listen, // /run/vmm-sandboxer.sock
14 &args.dir,
15 sandboxer, // 单一实例管理多个 sandbox
16 )
17 .await
18 .unwrap();
19}
性能优化的关键机制
优化效果饼图:
pie title 资源使用分布 (Kuasar vs 传统)
"轻量级 Shim 进程" : 5
"共享的 sandboxer 进程" : 95
-
消除重复开销
-
只有一个进程处理与 hypervisor 的交互
-
共享内存池和连接池
-
统一的 VM 生命周期管理
-
-
保持完整兼容性
-
containerd 仍然看到熟悉的 shim v2 接口
-
每个 sandbox 保持独立的进程边界
-
故障隔离和资源清理机制不变
-
-
99% 资源节省的实现
-
大部分 shim 实例从重量级变为轻量级
-
重量级的 VM 管理逻辑只有一份
-
避免重复的 hypervisor API 连接
-
生命周期管理流程
stateDiagram-v2
[*] --> SystemdStart: 系统启动
SystemdStart --> SandboxerReady: kuasar-vmm 服务启动
SandboxerReady --> ShimCreate: containerd 创建容器
state ShimCreate {
[*] --> ForkShim: fork 新的 shim 进程
ForkShim --> ConnectSandboxer: 连接到 sandboxer socket
ConnectSandboxer --> CreateVM: 通过 ttrpc 创建 microVM
CreateVM --> [*]
}
ShimCreate --> MultipleVMs: 可以创建多个 VM
state MultipleVMs {
VM1: Cloud Hypervisor 1
VM2: Cloud Hypervisor 2
VM3: Cloud Hypervisor 3
VM1 --> SandboxerManaged: 由同一个 sandboxer 管理
VM2 --> SandboxerManaged
VM3 --> SandboxerManaged
}
MultipleVMs --> ShimDelete: 容器删除
state ShimDelete {
[*] --> StopVM: 通知 sandboxer 停止 VM
StopVM --> CleanupShim: shim 进程退出
CleanupShim --> [*]
}
ShimDelete --> SandboxerReady: sandboxer 继续运行
SandboxerReady --> SystemdStop: 系统关闭
SystemdStop --> [*]
4 - 流程
4.1 - Cloud Hypervisor
4.1.1 - 启动
4.1.1.1 - 启动概述
Kuasar 中 Cloud Hypervisor microVM 启动全流程
1. 整体架构
Kuasar 通过以下组件实现 Cloud Hypervisor microVM 的管理:
- containerd-shim-kuasar-vmm-v2: containerd 的 shim 插件
- kuasar-vmm-sandboxer-clh: Cloud Hypervisor 专用的 sandbox 服务
- CloudHypervisorVM: VM 实例管理器
- CloudHypervisorVMFactory: VM 工厂类
2. 详细启动流程
第一阶段:Sandbox 创建 (create)
-
containerd 调用 shim
- containerd 通过 CRI API 调用
containerd-shim-kuasar-vmm-v2 - shim 连接到
kuasar-vmm-sandboxer-clh服务
- containerd 通过 CRI API 调用
-
Sandboxer 初始化
rustCopy code1// vmm/sandbox/src/bin/cloud_hypervisor/main.rs 2let mut sandboxer: KuasarSandboxer<CloudHypervisorVMFactory, CloudHypervisorHooks> = 3 KuasarSandboxer::new(config.sandbox, config.hypervisor, CloudHypervisorHooks::default()); -
VM 实例创建
rustCopy code1// CloudHypervisorVMFactory::create_vm 2let mut vm = CloudHypervisorVM::new(id, &netns, &s.base_dir, &self.vm_config); -
设备配置
- 添加 rootfs (pmem 设备):
Pmem::new("rootfs", &image_path, true) - 添加随机数生成器:
Rng::new("rng", &entropy_source) - 添加 vsock 设备:
Vsock::new(3, &guest_socket_path, "vsock") - 添加控制台设备:
Console::new(&console_path, "console") - 添加文件系统设备:
Fs::new("fs", &virtiofsd_socket, "kuasar")
- 添加 rootfs (pmem 设备):
-
Cgroup 设置
rustCopy code1sandbox_cgroups = SandboxCgroup::create_sandbox_cgroups(&cgroup_parent_path, &s.sandbox.id)?; 2sandbox_cgroups.update_res_for_sandbox_cgroups(&s.sandbox)?;
第二阶段:VM 启动 (start)
-
网络准备
rustCopy code1if !sandbox.data.netns.is_empty() { 2 sandbox.prepare_network().await?; 3} -
启动 virtiofsd
rustCopy code1async fn start_virtiofsd(&self) -> Result<u32> { 2 create_dir_all(&self.virtiofsd_config.shared_dir).await?; 3 let params = self.virtiofsd_config.to_cmdline_params("--"); 4 let mut cmd = tokio::process::Command::new(&self.virtiofsd_config.path); 5 cmd.args(params.as_slice()); 6 // 在指定的网络命名空间中启动 7 set_cmd_netns(&mut cmd, self.netns.to_string())?; 8} -
启动 Cloud Hypervisor
rustCopy code1async fn start(&mut self) -> Result<u32> { 2 let mut params = self.config.to_cmdline_params("--"); 3 for d in self.devices.iter() { 4 params.extend(d.to_cmdline_params("--")); 5 } 6 7 let mut cmd = tokio::process::Command::new(&self.config.path); 8 cmd.args(params.as_slice()); 9 set_cmd_netns(&mut cmd, self.netns.to_string())?; 10 let child = cmd.spawn()?; 11} -
API 客户端创建
rustCopy code1match self.create_client().await { 2 Ok(client) => self.client = Some(client), 3 Err(e) => return Err(e), 4};
第三阶段:Guest 系统配置
-
内核启动参数
rustCopy code1const DEFAULT_KERNEL_PARAMS: &str = "console=hvc0 \ 2root=/dev/pmem0p1 \ 3rootflags=data=ordered,errors=remount-ro \ 4ro rootfstype=ext4 \ 5task.sharefs_type=virtiofs"; -
Agent 通信建立
- VM 通过 vsock 设备与 host 通信
- agent_socket:
"hvsock://{guest_socket_path}:1024"
-
文件系统挂载
- rootfs 通过 pmem 设备挂载
- 共享目录通过 virtiofs 挂载
第四阶段:监控和管理
-
进程监控
rustCopy code1let sandbox_clone = sandbox_mutex.clone(); 2monitor(sandbox_clone); -
Cgroup 管理
rust Copy code 1sandbox.add_to_cgroup().await?;
3. 关键配置参数
VM 配置示例
tomlCopy code1[hypervisor]
2path = "/usr/local/bin/cloud-hypervisor"
3vcpus = 1
4memory_in_mb = 1024
5kernel_path = "/var/lib/kuasar/vmlinux.bin"
6image_path = "/var/lib/kuasar/kuasar.img"
7hugepages = true
8entropy_source = "/dev/urandom"
9
10[hypervisor.virtiofsd]
11path = "/usr/local/bin/virtiofsd"
12log_level = "info"
13cache = "never"
14thread_pool_size = 4
生成的 Cloud Hypervisor 命令行
bashCopy code1cloud-hypervisor \
2 --api-socket /path/to/api.sock \
3 --cpus boot=1 \
4 --memory size=1073741824,shared=on,hugepages=on \
5 --kernel /var/lib/kuasar/vmlinux.bin \
6 --cmdline "console=hvc0 root=/dev/pmem0p1 ..." \
7 --pmem file=/var/lib/kuasar/kuasar.img,id=rootfs,readonly=on \
8 --rng src=/dev/urandom,iommu=off \
9 --vsock cid=3,socket=/path/to/task.vsock \
10 --console file=/tmp/task.log \
11 --fs tag=kuasar,socket=/path/to/virtiofs.sock
4. 设备热插拔支持
Cloud Hypervisor 还支持设备的热插拔:
rustCopy code1async fn hot_attach(&mut self, device_info: DeviceInfo) -> Result<(BusType, String)> {
2 let client = self.get_client()?;
3 let addr = client.hot_attach(device_info)?;
4 Ok((BusType::PCI, addr))
5}
6
7async fn hot_detach(&mut self, id: &str) -> Result<()> {
8 let client = self.get_client()?;
9 client.hot_detach(id)?;
10 Ok(())
11}
5. 错误处理和恢复
系统具备完整的错误处理和恢复机制:
- 启动失败时自动清理网络和 cgroup
- 支持 sandbox 状态恢复
- 进程监控和异常退出处理
这个流程展示了 Kuasar 如何将 Cloud Hypervisor 集成到 containerd 生态系统中,提供了完整的 microVM 容器运行时解决方案。
4.1.1.2 - 文件
内容来自 code wiki.
文件传递
问: 仅仅考虑通过 cloud hypervisor 启动 microvm 的过程,kuasar 是如何将容器镜像,虚拟机 rootfs,kernel 等文件传递给 cloud hypervisor 并启动 microvm 实例的?
在 Kuasar 中,通过 Cloud Hypervisor 启动 MicroVM 实例时,容器镜像、虚拟机 rootfs 和 kernel 等文件通过以下方式传递和使用:
- 内核 (Kernel):
- Kuasar 针对不同的 VMMs(包括 Cloud Hypervisor)提供定制化的 Linux 内核构建框架,目的是优化内存占用和启动时间,主要采用“增量定制”方法,即只添加必要的特性,而不是从完整配置中删除功能,如 Linux Kernel Customization for MicroVMs 所述。
- 构建好的内核文件(例如
vmlinux.bin)会被放置在宿主机上的特定路径,例如/var/lib/kuasar/vmlinux.bin。 - 在启动
cloud-hypervisor进程时,kernel_path参数会被设置为这个文件的路径,从而将内核文件传递给 hypervisor,如vmm/sandbox/src/cloud_hypervisor/config.rs和vmm/sandbox/src/cloud_hypervisor/mod.rs中的CloudHypervisorConfig结构体所示。CloudHypervisorConfig的kernel字段直接引用了kernel_path。
- 虚拟机 Root Filesystem (Rootfs):
- Kuasar 提供了构建 guest OS rootfs 的脚本,如
vmm/scripts/image/build.sh,支持生成 rootfs 或完整的引导镜像,如 Guest OS Image and Root Filesystem Generation 所述。 - 构建好的 rootfs 镜像文件(例如
kuasar.img)也会被放置在宿主机上的特定路径,例如/var/lib/kuasar/kuasar.img。 CloudHypervisorVMFactory在创建 VM 实例时,如果image_path不为空,会将这个镜像文件作为Pmem设备添加到虚拟机中,其path字段指向image_path,如vmm/sandbox/src/cloud_hypervisor/factory.rs所示。这意味着 rootfs 是以持久内存(Pmem)设备的形式挂载到 MicroVM 中的,具体通过Pmem::new("rootfs", &self.vm_config.common.image_path, true)实现。
- Kuasar 提供了构建 guest OS rootfs 的脚本,如
- 容器镜像 (Container Image):
- Kuasar 的 MicroVM 沙箱通过
vmm-task进程在 guest VM 内部管理容器生命周期。容器镜像的内容通过virtio-fs设备共享给 guest VM,如 [MicroVM Sandbox (VMM)](#microvm-sandbox-vmm) 和 VMM Orchestration and Hypervisor Integration 所述。 - 在
CloudHypervisorVM::new方法中,会创建一个virtiofsd_config,其中socket_path和shared_dir会被配置,如vmm/sandbox/src/cloud_hypervisor/mod.rs所示。shared_dir通常是base_dir下的SHARED_DIR_SUFFIX目录。 CloudHypervisorVMFactory会在创建 VM 时,如果virtiofsd_config.socket_path不为空,则添加一个virtio-fs设备 (Fs::new),将其socket路径设置为virtiofsd_config.socket_path,并使用tag="kuasar"。这个virtio-fs设备允许 guest VM 访问宿主机上的共享目录,即容器镜像层叠文件系统等内容,如vmm/sandbox/src/cloud_hypervisor/factory.rs所示。virtiofsd进程由CloudHypervisorVM负责启动,它监听一个 socket 并在宿主机上共享virtiofsd_config.shared_dir目录,如vmm/sandbox/src/cloud_hypervisor/mod.rs中的start_virtiofsd方法所示。guest VM 通过virtio-fs驱动与virtiofsd进程通信,从而访问共享文件。DEFAULT_KERNEL_PARAMS中包含task.sharefs_type=virtiofs,这表明 guest 内核会启用 virtiofs 相关的参数,如vmm/sandbox/src/cloud_hypervisor/config.rs所示。
- Kuasar 的 MicroVM 沙箱通过
总结来说,Kuasar 通过以下机制将这些文件传递给 Cloud Hypervisor 并启动 MicroVM:
- 文件路径配置:内核和 rootfs 的路径在
CloudHypervisorVMConfig配置中指定,并在CloudHypervisorVM实例创建时用于构建cloud-hypervisor的命令行参数。 - 设备抽象:rootfs 作为
Pmem设备添加到虚拟机中,由CloudHypervisorVMFactory处理。 - VirtioFS 共享:容器镜像内容通过
virtio-fs共享机制传递。宿主机上运行的virtiofsd进程将宿主机上的共享目录暴露给 guest VM,guest VM 通过virtio-fs设备访问这些数据。
KuasarSandboxer 的 Cloud Hypervisor 后端入口点位于 vmm/sandbox/src/bin/cloud_hypervisor/main.rs。它加载配置 vmm/sandbox/src/cloud_hypervisor/config.rs,并使用 CloudHypervisorVMFactory vmm/sandbox/src/cloud_hypervisor/factory.rs 来创建和管理 CloudHypervisorVM 实例。实际启动 cloud-hypervisor 进程和 virtiofsd 进程的逻辑则在 CloudHypervisorVM vmm/sandbox/src/cloud_hypervisor/mod.rs 中实现。
Kernel 生成与传递
graph TD
subgraph Host System
A[Kuasar Build Environment] --> B(Linux Kernel Customization)
B --> C{build-kernel.sh}
C --Tailored Kernel Configuration--> D[Kernel Source Directory]
D --Kernel fragments--> E(Merge Kernel Fragments)
E --Final .config--> F(Kernel Compilation)
F --vmlinux.bin--> G[Kernel Binary: /var/lib/kuasar/vmlinux.bin]
end
subgraph Cloud Hypervisor VM Launch
G --> H{Cloud Hypervisor Process}
H --kernel_path parameter--> I[MicroVM Instance]
end
- 内核定制:Kuasar 为 Cloud Hypervisor 定制 Linux 内核。此过程采用“增量定制”方法,即只添加必要的特性,以优化内存占用和启动时间,如 Linux Kernel Customization for MicroVMs 所述。
- 构建脚本:
build-kernel.sh脚本 (vmm/scripts/kernel/build-kernel/build-kernel.sh) 负责整个内核构建过程。它根据目标架构 (--arch) 和内核类型 (--kernel-type) 动态选择配置片段。 - 配置合并:脚本使用 kernel build system utilities 合并这些配置片段,生成最终的
.config文件 (vmm/scripts/kernel/build-kernel/build-kernel.sh)。 - 内核编译:
.config文件用于编译内核,生成vmlinux.bin或bzImage,具体取决于 VMM 和架构,例如 Cloud Hypervisor 的vmlinux.bin。 - 文件放置:编译好的内核文件(如
vmlinux.bin)会被放置在宿主机上的特定路径,通常是/var/lib/kuasar/vmlinux.bin(docs/vmm/README.md)。 - 传递给 MicroVM:在启动
cloud-hypervisor进程时,Kuasar 会将kernel_path参数设置为这个内核文件的路径 (CloudHypervisorConfig在vmm/sandbox/src/cloud_hypervisor/config.rs)。Cloud Hypervisor 会加载此内核并启动 MicroVM 实例。
sequenceDiagram
participant KuasarBuildEnv as Kuasar Build Environment
participant BuildKernelSh as build-kernel.sh
participant KernelSourceDir as Kernel Source Directory
participant CloudHypervisorConfig as Cloud Hypervisor Config
participant CloudHypervisorVMM as Cloud Hypervisor VMM Process
participant MicroVMGuest as MicroVM Guest
KuasarBuildEnv->>BuildKernelSh: 启动内核构建
BuildKernelSh->>KernelSourceDir: 根据架构/类型选择内核片段
KernelSourceDir-->>BuildKernelSh: 提供内核片段
BuildKernelSh->>BuildKernelSh: 合并片段生成 .config
BuildKernelSh->>BuildKernelSh: 编译内核 (vmlinux.bin)
BuildKernelSh-->>KuasarBuildEnv: 输出 vmlinux.bin 到 /var/lib/kuasar/vmlinux.bin
KuasarBuildEnv->>CloudHypervisorConfig: 配置 kernel_path = /var/lib/kuasar/vmlinux.bin
CloudHypervisorConfig->>CloudHypervisorVMM: 将 kernel_path 作为参数传递给 Cloud Hypervisor
CloudHypervisorVMM->>MicroVMGuest: 加载 vmlinux.bin 作为 guest 内核
Root Filesystem 生成与传递
graph TD
subgraph Host System
A[Kuasar Build Environment] --> B(Guest OS Rootfs Build Scripts)
B --build.sh--> C{Containerized Build Environment}
C --centos/build_rootfs.sh--> D[Install Rust & Go]
D --> E(Compile vmm-task & runc)
E --> F[Populate Rootfs Directory: /tmp/kuasar-rootfs]
F --build_image.sh--> G[Validate Rootfs]
G --> H(Create Raw Disk Image)
H --> I(Partition & Format)
I --Copy Rootfs Content--> J[Rootfs Image: /var/lib/kuasar/kuasar.img]
J --Optional: nsdax utility--> K(NVDIMM/DAX Header Configuration)
K --> J
end
subgraph Cloud Hypervisor VM Launch
J --> L{Cloud Hypervisor Process}
L --image_path parameter (as Pmem device)--> M[MicroVM Instance]
end
- Rootfs 构建脚本:Kuasar 使用
vmm/scripts/image/build.sh脚本来构建 guest OS 的 root filesystem。这个脚本可以在容器化环境中执行构建过程 (vmm/scripts/image/build.sh)。 - 具体构建过程:CentOS-based 的 rootfs 通过
vmm/scripts/image/centos/build_rootfs.sh脚本构建 (vmm/scripts/image/centos/build_rootfs.sh)。这包括:- 安装 Rust 工具链 (
install_rust.sh) (vmm/scripts/image/install_rust.sh)。 - 构建 Kuasar 的
vmm-task(vmm/scripts/image/centos/build_rootfs.sh)。 - 安装 Go 运行时,编译
runc(vmm/scripts/image/centos/build_rootfs.sh)。 - 将这些二进制文件、
glibc库和 RPM 包复制到临时 rootfs 目录 (vmm/scripts/image/centos/build_rootfs.sh)。
- 安装 Rust 工具链 (
- 镜像生成:
vmm/scripts/image/build_image.sh脚本 (vmm/scripts/image/build_image.sh) 负责将 rootfs 目录转换为一个完整的 Kata Containers 兼容的 rootfs 镜像:- 它验证 rootfs 内容,计算所需磁盘大小。
- 使用
qemu-img创建原始磁盘镜像。 - 使用
parted对镜像进行分区并格式化 (vmm/scripts/image/build_image.sh)。 - 将 rootfs 内容复制到分区中。
- 可选地,使用
nsdax工具配置 NVDIMM/DAX 头,以支持持久内存功能 (vmm/scripts/image/build_image.sh)。
- 文件放置:生成的 rootfs 镜像文件(如
kuasar.img)会被放置在宿主机上的特定路径,通常是/var/lib/kuasar/kuasar.img(docs/vmm/README.md)。 - 传递给 MicroVM:
CloudHypervisorVMFactory在创建 VM 实例时,如果image_path不为空,会将这个镜像文件作为Pmem设备添加到虚拟机中。这意味着 rootfs 是以持久内存设备的形式挂载到 MicroVM 中的。
sequenceDiagram
participant KuasarBuildEnv as Kuasar Build Environment
participant BuildSh as build.sh
participant CentOSBuildRootfsSh as centos/build_rootfs.sh
participant TmpRootfsDir as /tmp/kuasar-rootfs (Temporary)
participant BuildImageSh as build_image.sh
participant QemuImgParted as qemu-img / parted
participant NsdaxUtility as nsdax utility (Optional)
participant CloudHypervisorConfig as Cloud Hypervisor Config
participant CloudHypervisorVMM as Cloud Hypervisor VMM Process
participant MicroVMGuest as MicroVM Guest
KuasarBuildEnv->>BuildSh: 启动 rootfs 构建 (例如通过 containerd/docker 容器)
BuildSh->>CentOSBuildRootfsSh: 在容器内执行具体构建逻辑
CentOSBuildRootfsSh->>CentOSBuildRootfsSh: 安装 Rust & Go
CentOSBuildRootfsSh->>CentOSBuildRootfsSh: 编译 vmm-task & runc
CentosBuildRootfsSh->>TmpRootfsDir: 填充临时 rootfs 目录
CentosBuildRootfsSh-->>BuildSh: 完成临时 rootfs 准备
BuildSh->>BuildImageSh: 启动镜像生成脚本
BuildImageSh->>BuildImageSh: 验证 rootfs
BuildImageSh->>QemuImgParted: 创建原始磁盘镜像,分区,格式化
QemuImgParted->>TmpRootfsDir: 从临时 rootfs 目录复制内容到磁盘镜像
BuildImageSh->>NsdaxUtility: (可选) 配置 NVDIMM/DAX 头
NsdaxUtility-->>BuildImageSh: 返回更新后的镜像
BuildImageSh-->>KuasarBuildEnv: 输出 kuasar.img 到 /var/lib/kuasar/kuasar.img
KuasarBuildEnv->>CloudHypervisorConfig: 配置 image_path = /var/lib/kuasar/kuasar.img
CloudHypervisorConfig->>CloudHypervisorVMM: 将 image_path 作为 Pmem 设备参数传递
CloudHypervisorVMM->>MicroVMGuest: 挂载 Pmem 设备作为 guest rootfs
容器镜像传递到 MicroVM
graph TD
subgraph Host System
A[Containerd / iSulad Runtime] --> B(Container Image Layers)
B --> C{Shared Directory: /base_dir/shared_dir_suffix}
C --virtiofsd process--> D[virtiofsd Socket: /base_dir/virtiofs.sock]
D --vmm-sandboxer configures--> E{Cloud Hypervisor Process}
E --virtio-fs device--> F[MicroVM Instance]
end
subgraph Guest MicroVM
F --virtio-fs driver in guest kernel--> G[Guest OS]
G --Mount Shared Directory--> H[Container Rootfs Available]
H --vmm-task process in guest--> I(Container Runtime Operations)
end
- 共享目录:Kuasar 的 MicroVM 沙箱通过
virtio-fs设备共享机制将容器镜像内容传递给 guest VM。在CloudHypervisorVM的new方法中,会为virtiofsd配置一个shared_dir(vmm/sandbox/src/cloud_hypervisor/mod.rs),这个目录通常是 sandbox 的base_dir下的SHARED_DIR_SUFFIX(vmm/common/src/lib.rs)。容器镜像的层叠文件系统等内容会被准备到这个共享目录中。 - 启动 virtiofsd:
CloudHypervisorVM(vmm/sandbox/src/cloud_hypervisor/mod.rs) 负责启动virtiofsd进程 (start_virtiofsd方法)。virtiofsd进程监听一个 Unix socket (socket_path) (vmm/sandbox/src/cloud_hypervisor/mod.rs) 并将宿主机上的shared_dir暴露出来。 - Virtio-FS 设备添加:
CloudHypervisorVMFactory(vmm/sandbox/src/cloud_hypervisor/factory.rs) 在创建 VM 时,会添加一个virtio-fs设备,将其socket路径设置为virtiofsd_config.socket_path,并使用tag="kuasar"。 - Guest VM 访问:Guest VM 中的
vmm-task(docs/vmm/README.md) 作为 PID 1 进程,负责管理容器生命周期。它会利用 guest 内核中的virtio-fs驱动通过这个virtio-fs设备与宿主机上的virtiofsd进程通信,从而访问共享文件,并作为容器的 rootfs 使用。DEFAULT_KERNEL_PARAMS中包含task.sharefs_type=virtiofs(vmm/sandbox/src/stratovirt/config.rs) 确保 guest 内核启用virtiofs相关参数。
sequenceDiagram
participant HostSystem as Host System
participant ContainerdIsuadRuntime as Containerd/iSulad Runtime
participant SharedDirectory as Shared Directory (/base_dir/shared_dir_suffix)
participant VirtiofsdProcess as virtiofsd Process
participant VMMController as vmm-sandboxer (CloudHypervisorVM)
participant CloudHypervisorVMM as Cloud Hypervisor VMM Process
participant MicroVMGuest as MicroVM Guest
participant VMMTaskProcess as vmm-task (PID 1 in Guest)
ContainerdIsuadRuntime->>SharedDirectory: 准备/提取容器镜像层叠文件系统到共享目录
VMMController->>SharedDirectory: (通过 virtiofsd_config.shared_dir 配置)
VMMController->>VirtiofsdProcess: 启动 virtiofsd 进程 (通过 start_virtiofsd 方法)
VirtiofsdProcess->>VirtiofsdProcess: 监听 Unix Socket (/base_dir/virtiofs.sock) 并提供共享目录服务
VMMController->>CloudHypervisorVMM: 添加 virtio-fs 设备,指定 socket_path 和 tag="kuasar"
CloudHypervisorVMM->>MicroVMGuest: 模拟 virtio-fs 设备,连接到宿主机上的 virtiofsd socket
MicroVMGuest->>VMMTaskProcess: Guest 内核启动参数包含 task.sharefs_type=virtiofs
VMMTaskProcess->>MicroVMGuest: 通过 guest 内核中的 virtio-fs 驱动挂载共享目录
MicroVMGuest-->>SharedDirectory: Guest OS 通过 virtio-fs 挂载访问容器 rootfs
VMMTaskProcess->>VMMTaskProcess: 管理容器生命周期,使用共享的 rootfs
容器镜像共享
问:请详细介绍一下kuasar启动 cloud hypervisor 的 microvm 的过程中,容器镜像是如何共享的,最好用 mermaid 画序列图来帮助理解整个过程。
在 Kuasar 启动 Cloud Hypervisor microVM 的过程中,容器镜像的共享主要通过 virtio-fs 设备进行。vmm-sandboxer 作为 containerd 的沙箱插件,负责管理沙箱生命周期。当创建一个新的沙箱时,它会启动 Cloud Hypervisor 虚拟机并在其中运行 vmm-task 作为 PID 1 进程,virtiofsd 作为辅助进程。容器镜像(rootfs)通过 virtio-fs 挂载到 guest VM 内部,供 vmm-task 和 runc 使用。
以下是容器镜像共享的详细过程及序列图:
containerd-shim请求创建沙箱和容器containerd-shim接收到创建容器的请求。containerd-shim通过ttrpc调用vmm-sandboxer的CreateSandbox方法。
vmm-sandboxer准备Cloud Hypervisor虚拟机vmm-sandboxer(vmm/sandbox/src/bin/cloud_hypervisor/main.rs) 根据配置 (vmm/sandbox/config_clh.toml) 初始化CloudHypervisorVM实例。CloudHypervisorVM实例会配置virtiofsd的相关信息,包括socket_path和shared_dir。shared_dir会被设置为base_dir/SHARED_DIR_SUFFIX(vmm/sandbox/src/cloud_hypervisor/mod.rs),这个目录将在宿主机上用于存放共享文件。vmm-sandboxer创建CloudHypervisorVM实例时,会添加virtio-fs设备。这个Fs设备 (vmm/sandbox/src/cloud_hypervisor/devices/fs.rs) 使用virtiofsd_config.socket_path和一个tag("kuasar")。
virtiofsd启动- 在
CloudHypervisorVM::start方法中 (vmm/sandbox/src/cloud_hypervisor/mod.rs),vmm-sandboxer会启动virtiofsd进程。 virtiofsd进程会使用virtiofsd_config.shared_dir作为其共享目录,并通过socket_path对外提供服务。virtiofsd会创建一个 Unix Domain Socket 监听连接,等待Cloud Hypervisor连接。
- 在
Cloud Hypervisor启动并连接virtiofsdvmm-sandboxer构建Cloud Hypervisor命令行参数,并启动Cloud Hypervisor虚拟机。Cloud Hypervisor启动时,会根据配置的virtio-fs设备信息,连接到virtiofsd创建的 Unix Domain Socket。Cloud Hypervisor在 guest VM 内部暴露一个virtio-fs设备。
vmm-task启动并挂载virtio-fsCloud Hypervisor启动 guest VM,并在 guest VM 内部启动vmm-task(vmm/task/src/main.rs) 作为 PID 1 进程。vmm-task会解析Cloud Hypervisor传递的kernel_params。其中包含task.sharefs_type=virtiofs(vmm/sandbox/src/cloud_hypervisor/config.rs),指示使用virtio-fs进行文件共享。vmm-task将virtio-fs设备挂载到KUASAR_GUEST_SHARE_DIR(/run/kuasar/storage/containers/) 路径下,使用的tag为"kuasar"(DEFAULT_KERNEL_PARAMS中包含rootfstype=ext4 task.sharefs_type=virtiofs)。- 挂载成功后,
vmm-task就可以通过KUASAR_GUEST_SHARE_DIR访问宿主机上vmm-sandboxer的base_dir/SHARED_DIR_SUFFIX目录中的文件。
- 容器镜像共享
- 当
containerd-shim请求创建容器时,vmm-sandboxer会处理Mount信息。 - 对于容器的
rootfs和bind mounts,vmm-sandboxer会根据类型进行处理 (vmm/sandbox/src/storage/mod.rs)。 - 如果
rootfs或bind mount关联到Storage并且need_guest_handle为true,vmm-sandboxer会将这些Storage信息序列化,并通过ANNOTATION_KEY_STORAGE注解传递给vmm-task。 vmm-sandboxer会在宿主机的base_dir/SHARED_DIR_SUFFIX目录下创建必要的目录结构或文件,并将宿主机上的mount point绑定到这些目录或文件上 (vmm/sandbox/src/storage/mod.rs)。vmm-task接收到容器创建请求后,会解析ANNOTATION_KEY_STORAGE获取Storage列表 (vmm/task/src/container.rs)。vmm-task会根据Storage信息,将KUASAR_GUEST_SHARE_DIR下对应的目录作为容器的rootfs或bind mount的源路径 (vmm/task/src/sandbox.rs)。
- 当
通过上述步骤,宿主机上的容器镜像(以及其他需要共享的文件)通过 virtio-fs 机制,以文件系统挂载的方式透明地共享给 guest VM 中的容器。
sequenceDiagram
participant Containerd
participant ContainerdShim
participant VmmSandboxer
participant CloudHypervisor
participant Virtiofsd
participant VmmTask
participant Runc
Containerd->>ContainerdShim: CreateContainer Request (OCI Bundle)
ContainerdShim->>VmmSandboxer: CreateSandbox/Container (ttrpc)
VmmSandboxer->>VmmSandboxer: Initialize CloudHypervisorVM
VmmSandboxer->>VmmSandboxer: Configure virtio-fs device (socket_path, shared_dir)
VmmSandboxer->>Virtiofsd: Start virtiofsd (shared_dir=base_dir/shared_suffix, socket_path)
activate Virtiofsd
Virtiofsd->>Virtiofsd: Create Unix Domain Socket
VmmSandboxer->>CloudHypervisor: Start Cloud Hypervisor VM (kernel, image, virtio-fs device, kernel_params="...task.sharefs_type=virtiofs...")
activate CloudHypervisor
CloudHypervisor->>Virtiofsd: Connect to virtiofsd Unix Domain Socket
CloudHypervisor->>VmmTask: Launch Guest VM & VmmTask (PID 1)
activate VmmTask
VmmTask->>VmmTask: Parse kernel_params (task.sharefs_type=virtiofs)
VmmTask->>VmmTask: Mount virtio-fs device to /run/kuasar/storage/containers/
VmmTask-->>CloudHypervisor: Mount successful
VmmSandboxer->>VmmSandboxer: Process container Mounts (rootfs, bind mounts)
VmmSandboxer->>VmmSandboxer: Create host shared directories/files (in base_dir/shared_suffix)
VmmSandboxer->>VmmSandboxer: Bind mount host paths to shared directories
VmmSandboxer->>VmmTask: CreateContainer (ttrpc, with ANNOTATION_KEY_STORAGE)
VmmTask->>VmmTask: Read ANNOTATION_KEY_STORAGE
VmmTask->>VmmTask: Identify container rootfs/mounts from /run/kuasar/storage/containers/
VmmTask->>Runc: CreateContainer (OCI Spec with adjusted rootfs/mount paths)
activate Runc
Runc->>VmmTask: Container created
deactivate Runc
VmmTask->>ContainerdShim: Container created response
ContainerdShim->>Containerd: Container created response
4.1.1.3 - cgroup
内容来自 code wiki.
cgroup
问:当我在一个 bms 上创建多个 cloud hypervisor 的 microvm 时,cgroup 是如何设计的?什么时候创建 cgroup?
当在 bare-metal server (BMS) 上创建多个 Cloud Hypervisor microVM 时,Kuasar 会为每个 sandbox 设计和管理 cgroup,以实现资源隔离和控制。
Cgroup 的设计和创建时间
- Sandbox Cgroup 的创建:
- 当
KuasarSandboxer收到创建 sandbox 的请求时,它会首先尝试为该 sandbox 创建 cgroup。 - 在
KuasarSandboxer的create方法中 (kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs),会调用SandboxCgroup::create_sandbox_cgroups函数 (kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs)。 - 这个函数会创建一个主 sandbox cgroup,路径格式为
{cgroup_parent_path}/{sandbox_id}。默认的cgroup_parent_path是"kuasar-vmm"(kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs),但也可以通过PodSandboxConfig中的cgroup_parent字段来指定,例如 Kubernetes 环境下可能为/kubepods/burstable/podxxx(kuasar-io/kuasar/vmm/sandbox/src/cgroup.rscreate_mock_pod_sandbox_config函数)。 - 除了主 sandbox cgroup,还会创建两个子 cgroup:
vcpucgroup (kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs),用于管理 vCPU 相关的 CPU 资源。pod_overheadcgroup (kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs),用于管理 pod overhead 相关的 CPU 资源。
- 创建时机: 这些 cgroup 在
KuasarSandboxer处理CreateSandbox请求时,VM 启动之前被创建。
- 当
- 资源限制的应用:
- cgroup 创建后,
KuasarSandboxer会调用sandbox_cgroups.update_res_for_sandbox_cgroups(kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs) 来应用资源限制。 - 这个函数 (
kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs) 会根据SandboxData中定义的资源 (LinuxContainerResources) 对主 sandbox cgroup 应用 CPU、内存、cpuset 和 hugetlb 资源限制。 vcpu和pod_overheadcgroup 仅应用 CPU 资源限制 (kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs)。- 应用时机: 资源限制在 sandbox cgroup 创建后立即应用,同样在 VM 启动之前。
- cgroup 创建后,
- VMM 进程和 VCPU 线程加入 Cgroup:
- 当 MicroVM 启动后,
vmm-sandboxer会获取 VMM 进程的 PID 和其 vCPU 线程的 PID (kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs)。 - 它会调用
sandbox_cgroups.add_process_into_sandbox_cgroups(kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs):- 将 VMM 主进程加入到主 sandbox cgroup 和
pod_overheadcgroup 中。 - 将所有 vCPU 线程加入到
vcpucgroup 中。
- 将 VMM 主进程加入到主 sandbox cgroup 和
- 加入时机: VMM 进程和 VCPU 线程在 MicroVM 启动并获取到其 PID 后,通过
add_to_cgroup方法 (kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs) 加入到相应的 cgroup 中。
- 当 MicroVM 启动后,
- Cgroup V1 和 V2 的支持:
- 目前 Kuasar 主要支持 cgroup V1 (
kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs)。 vmm-task(PID 1在 Guest VM 内) 也会处理 cgroup 的挂载配置,get_cgroup_mounts函数 (kuasar-io/kuasar/vmm/task/src/mount.rs) 会根据unified_cgroup_hierarchy参数生成 cgroup 挂载点,支持 cgroup v1 和 v2 两种模式,确保 Guest VM 内的 cgroup 视图正确。
- 目前 Kuasar 主要支持 cgroup V1 (
- Cgroup 的清理:
- 当 sandbox 被删除时,
KuasarSandboxer会调用sandbox_cgroups.remove_sandbox_cgroups(kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs) 来清理所有相关的 cgroup。 - 清理过程包括将 cgroup 中的任务移动到父 cgroup,然后删除子 cgroup 和主 cgroup。
- 清理时机: 在
KuasarSandboxer的delete方法中 (kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs)。
- 当 sandbox 被删除时,
总结:
Kuasar 在创建每个 MicroVM sandbox 时,会在宿主机上动态创建一套分层的 cgroup 结构 (sandbox -> vcpu/pod_overhead)。这些 cgroup 在 VM 启动前创建并配置资源限制,在 VM 启动后将 VMM 进程和 vCPU 线程加入相应的 cgroup 进行管理,以确保每个 MicroVM 及其内部组件都运行在预定义的资源限制内,从而实现多个 MicroVM 在 BMS 上的隔离和高效运行。
sequenceDiagram
participant KuasarSandboxer
participant SandboxCgroup
participant MicroVM
participant VMMProcess
participant VCPUThreads
KuasarSandboxer->>SandboxCgroup: create_sandbox_cgroups(cgroup_parent_path, sandbox_id)
activate SandboxCgroup
SandboxCgroup->>SandboxCgroup: Create main sandbox cgroup ({parent_path}/{sandbox_id})
SandboxCgroup->>SandboxCgroup: Create vcpu cgroup ({sandbox_id}/vcpu) (CPU subsystem only)
SandboxCgroup->>SandboxCgroup: Create pod_overhead cgroup ({sandbox_id}/pod_overhead) (CPU subsystem only)
deactivate SandboxCgroup
KuasarSandboxer->>SandboxCgroup: update_res_for_sandbox_cgroups(sandbox_data)
activate SandboxCgroup
SandboxCgroup->>SandboxCgroup: Apply CPU, Memory, CPUSet, HugeTlb limits to main sandbox cgroup
SandboxCgroup->>SandboxCgroup: Apply CPU limits to vcpu cgroup
SandboxCgroup->>SandboxCgroup: Apply CPU limits to pod_overhead cgroup
deactivate SandboxCgroup
KuasarSandboxer->>MicroVM: Start MicroVM (e.g., Cloud Hypervisor)
activate MicroVM
MicroVM->>VMMProcess: Launch VMM process
VMMProcess->>VCPUThreads: Spawn VCPU threads
MicroVM-->>KuasarSandboxer: VMM Process PID, VCPU Thread PIDs
KuasarSandboxer->>SandboxCgroup: add_process_into_sandbox_cgroups(VMM_PID, VCPU_TIDs)
activate SandboxCgroup
SandboxCgroup->>SandboxCgroup: Add VMM_PID to main sandbox cgroup
SandboxCgroup->>SandboxCgroup: Add VMM_PID to pod_overhead cgroup
SandboxCgroup->>SandboxCgroup: Add VCPU_TIDs to vcpu cgroup
deactivate SandboxCgroup
KuasarSandboxer->>KuasarSandboxer: MicroVM and containers run with cgroup isolation
alt Sandbox Deletion
KuasarSandboxer->>SandboxCgroup: remove_sandbox_cgroups()
activate SandboxCgroup
SandboxCgroup->>SandboxCgroup: Move all tasks from cgroups to parent
SandboxCgroup->>SandboxCgroup: Delete vcpu cgroup
SandboxCgroup->>SandboxCgroup: Delete pod_overhead cgroup
SandboxCgroup->>SandboxCgroup: Delete main sandbox cgroup
deactivate SandboxCgroup
end
4.1.1.4 - vmm task
vmm task 启动
问:cloud hypervisor 的 microvm 里面的 kuasar agent,是通过什么方式启动的?systemd,还是 init 脚本?
在 Cloud Hypervisor MicroVM 内部,Kuasar agent (即 vmm-task) 是作为 PID 1 进程启动的,它会处理操作系统的初始化和信号,而不是通过传统的 systemd 或 init 脚本启动。
以下是 vmm-task 启动方式的详细说明:
- 作为 PID 1 启动:根据 [MicroVM Sandbox (
VMM)](#microvm-sandbox-vmm) 和 VMM Task Lifecycle and Runtime Management 描述,vmm-task在 Guest VM 内部作为 PID 1 进程运行。这意味着它是 Guest OS 启动后执行的第一个用户空间进程,负责管理容器和进程的生命周期,以及处理资源分配、网络配置和异步 I/O 操作。 - 初始化 VM 环境:
vmm-task的主要入口点在kuasar-io/kuasar/vmm/task/src/main.rs。这个组件会初始化 VM 的环境,设置必要的文件系统和内核参数。它还配置了一个ttrpc服务器,用于暴露服务以管理任务、沙箱和流,允许外部组件与 VM 的内部进程进行交互。 - 处理操作系统信号:作为 PID 1 进程,
vmm-task还负责处理操作系统信号,包括回收子进程和管理优雅关机,这在kuasar-io/kuasar/vmm/task/src/main.rs的handle_signals函数中有体现。 - 配置通过内核命令行参数:
vmm-task的配置参数由TaskConfig结构管理,该结构在kuasar-io/kuasar/vmm/task/src/config.rs中定义。这些配置是通过解析来自/proc/cmdline的内核命令行参数动态确定的,允许在运行时灵活调整,而无需依赖外部配置文件。例如,通过kernel_params = "task.debug"可以在vmm-task中启用调试控制台功能。如docs/vmm/README.md中“Developer Guide”部分的“Set up a debug console”所述,task.debug会作为kernel_params传递。
因此,Kuasar agent (vmm-task) 不依赖 systemd 或传统的 init 脚本在 Guest VM 中启动,而是直接作为 MicroVM 的 PID 1 进程运行,并根据内核命令行参数进行配置和初始化。
sequenceDiagram
participant CloudHypervisor
participant GuestKernel
participant VmmTask
CloudHypervisor->>GuestKernel: Boot Guest VM (kernel, initrd, kernel_params="...task.sharefs_type=virtiofs task.debug=true...")
activate GuestKernel
GuestKernel->>VmmTask: Execute vmm-task as PID 1
activate VmmTask
VmmTask->>VmmTask: `initialize()` function in `main.rs`
VmmTask->>VmmTask: Call `TaskConfig::new()`
VmmTask->>VmmTask: Parse kernel command-line arguments from `/proc/cmdline` to create `TaskConfig`
VmmTask->>VmmTask: Set tracing (if `config.enable_tracing` is true)
VmmTask->>VmmTask: Initialize logger (`init_logger`)
VmmTask->>VmmTask: Call `early_init_call()`
VmmTask->>VmmTask: Setup environment variables from `ENVS`
VmmTask->>VmmTask: Initialize VM rootfs (`init_vm_rootfs()`)
VmmTask->>VmmTask: Mount static mounts (e.g., `/proc`, `/sys`, `/dev`, `/run`, `/dev/shm`, `/dev/pts`)
VmmTask->>VmmTask: Mount cgroup filesystems based on `get_cgroup_mounts`
VmmTask->>VmmTask: Set default `sysctl` parameters (e.g., `vm.overcommit_memory`)
alt Sharefs Type is "virtiofs"
VmmTask->>VmmTask: Mount `SHAREFS_VIRTIOFS_MOUNTS` (e.g., `virtiofs` for `KUASAR_STATE_DIR`)
else Sharefs Type is "9p"
VmmTask->>VmmTask: Mount `SHAREFS_9P_MOUNTS` (e.g., `9p` for `KUASAR_STATE_DIR`)
end
alt Debug Mode Enabled (`config.debug` is true)
VmmTask->>VmmTask: Call `listen_debug_console("vsock://-1:1025", &config.debug_shell)`
end
VmmTask->>VmmTask: Call `late_init_call()`
VmmTask->>VmmTask: Setup DNS by bind mounting `KUASAR_STATE_DIR/RESOLV_FILENAME` to `/etc/resolv.conf` (if exists)
VmmTask->>VmmTask: Create TTRPC Server (`create_ttrpc_server()`)
VmmTask->>VmmTask: Create `TaskService`
VmmTask->>VmmTask: Create `SandboxService`
VmmTask->>VmmTask: Create `StreamingService`
VmmTask->>VmmTask: Register services and bind to `vsock://-1:1024`
VmmTask->>VmmTask: Start TTRPC Server
VmmTask->>VmmTask: Listen for OS signals (`handle_signals()`)
loop Signal Handling
VmmTask->>VmmTask: Handle `SIGTERM`, `SIGINT`, `SIGCHLD`, `SIGUSR1`, etc.
alt SIGCHLD
VmmTask->>VmmTask: `waitpid()` for child processes
VmmTask->>VmmTask: Notify monitor about child exit/termination
end
alt SIGUSR1
VmmTask->>VmmTask: Toggle tracing and re-initialize logger
end
end