文件

启动 Cloud Hypervisor 过程中的文件传递

内容来自 code wiki.


文件传递

问: 仅仅考虑通过 cloud hypervisor 启动 microvm 的过程,kuasar 是如何将容器镜像,虚拟机 rootfs,kernel 等文件传递给 cloud hypervisor 并启动 microvm 实例的?

在 Kuasar 中,通过 Cloud Hypervisor 启动 MicroVM 实例时,容器镜像、虚拟机 rootfs 和 kernel 等文件通过以下方式传递和使用:

  1. 内核 (Kernel)
  2. 虚拟机 Root Filesystem (Rootfs)
  3. 容器镜像 (Container Image)

总结来说,Kuasar 通过以下机制将这些文件传递给 Cloud Hypervisor 并启动 MicroVM:

  1. 文件路径配置:内核和 rootfs 的路径在 CloudHypervisorVMConfig 配置中指定,并在 CloudHypervisorVM 实例创建时用于构建 cloud-hypervisor 的命令行参数。
  2. 设备抽象:rootfs 作为 Pmem 设备添加到虚拟机中,由 CloudHypervisorVMFactory 处理。
  3. 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
  1. 内核定制:Kuasar 为 Cloud Hypervisor 定制 Linux 内核。此过程采用“增量定制”方法,即只添加必要的特性,以优化内存占用和启动时间,如 Linux Kernel Customization for MicroVMs 所述。
  2. 构建脚本build-kernel.sh 脚本 ( vmm/scripts/kernel/build-kernel/build-kernel.sh ) 负责整个内核构建过程。它根据目标架构 (--arch) 和内核类型 (--kernel-type) 动态选择配置片段。
  3. 配置合并:脚本使用 kernel build system utilities 合并这些配置片段,生成最终的 .config 文件 ( vmm/scripts/kernel/build-kernel/build-kernel.sh )。
  4. 内核编译.config 文件用于编译内核,生成 vmlinux.binbzImage,具体取决于 VMM 和架构,例如 Cloud Hypervisor 的 vmlinux.bin
  5. 文件放置:编译好的内核文件(如 vmlinux.bin)会被放置在宿主机上的特定路径,通常是 /var/lib/kuasar/vmlinux.bin ( docs/vmm/README.md )。
  6. 传递给 MicroVM:在启动 cloud-hypervisor 进程时,Kuasar 会将 kernel_path 参数设置为这个内核文件的路径 ( CloudHypervisorConfigvmm/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
  1. Rootfs 构建脚本:Kuasar 使用 vmm/scripts/image/build.sh 脚本来构建 guest OS 的 root filesystem。这个脚本可以在容器化环境中执行构建过程 ( vmm/scripts/image/build.sh )。
  2. 具体构建过程:CentOS-based 的 rootfs 通过 vmm/scripts/image/centos/build_rootfs.sh 脚本构建 ( vmm/scripts/image/centos/build_rootfs.sh )。这包括:
  3. 镜像生成vmm/scripts/image/build_image.sh 脚本 ( vmm/scripts/image/build_image.sh ) 负责将 rootfs 目录转换为一个完整的 Kata Containers 兼容的 rootfs 镜像:
  4. 文件放置:生成的 rootfs 镜像文件(如 kuasar.img)会被放置在宿主机上的特定路径,通常是 /var/lib/kuasar/kuasar.img ( docs/vmm/README.md )。
  5. 传递给 MicroVMCloudHypervisorVMFactory 在创建 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
  1. 共享目录:Kuasar 的 MicroVM 沙箱通过 virtio-fs 设备共享机制将容器镜像内容传递给 guest VM。在 CloudHypervisorVMnew 方法中,会为 virtiofsd 配置一个 shared_dir ( vmm/sandbox/src/cloud_hypervisor/mod.rs ),这个目录通常是 sandbox 的 base_dir 下的 SHARED_DIR_SUFFIX ( vmm/common/src/lib.rs )。容器镜像的层叠文件系统等内容会被准备到这个共享目录中。
  2. 启动 virtiofsdCloudHypervisorVM ( vmm/sandbox/src/cloud_hypervisor/mod.rs ) 负责启动 virtiofsd 进程 (start_virtiofsd 方法)。virtiofsd 进程监听一个 Unix socket (socket_path) ( vmm/sandbox/src/cloud_hypervisor/mod.rs ) 并将宿主机上的 shared_dir 暴露出来。
  3. Virtio-FS 设备添加CloudHypervisorVMFactory ( vmm/sandbox/src/cloud_hypervisor/factory.rs ) 在创建 VM 时,会添加一个 virtio-fs 设备,将其 socket 路径设置为 virtiofsd_config.socket_path,并使用 tag="kuasar"
  4. 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-taskrunc 使用。

以下是容器镜像共享的详细过程及序列图:

  1. containerd-shim 请求创建沙箱和容器
  2. vmm-sandboxer 准备 Cloud Hypervisor 虚拟机
  3. virtiofsd 启动
  4. Cloud Hypervisor 启动并连接 virtiofsd
  5. vmm-task 启动并挂载 virtio-fs
  6. 容器镜像共享

通过上述步骤,宿主机上的容器镜像(以及其他需要共享的文件)通过 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