文件
内容来自 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