这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

流程

Kuasar 功能和流程分析

1 - Cloud Hypervisor

Kuasar 中使用 Cloud Hypervisor 的流程

1.1 - 启动

启动 Cloud Hypervisor

1.1.1 - 启动概述

启动 Cloud Hypervisor 的流程概述

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)

  1. containerd 调用 shim

    • containerd 通过 CRI API 调用 containerd-shim-kuasar-vmm-v2
    • shim 连接到 kuasar-vmm-sandboxer-clh 服务
  2. 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());
    
  3. VM 实例创建

    rustCopy code1// CloudHypervisorVMFactory::create_vm
    2let mut vm = CloudHypervisorVM::new(id, &netns, &s.base_dir, &self.vm_config);
    
  4. 设备配置

    • 添加 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")
  5. 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)

  1. 网络准备

    rustCopy code1if !sandbox.data.netns.is_empty() {
    2    sandbox.prepare_network().await?;
    3}
    
  2. 启动 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}
    
  3. 启动 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}
    
  4. API 客户端创建

    rustCopy code1match self.create_client().await {
    2    Ok(client) => self.client = Some(client),
    3    Err(e) => return Err(e),
    4};
    

第三阶段:Guest 系统配置

  1. 内核启动参数

    rustCopy code1const DEFAULT_KERNEL_PARAMS: &str = "console=hvc0 \
    2root=/dev/pmem0p1 \
    3rootflags=data=ordered,errors=remount-ro \
    4ro rootfstype=ext4 \
    5task.sharefs_type=virtiofs";
    
  2. Agent 通信建立

    • VM 通过 vsock 设备与 host 通信
    • agent_socket: "hvsock://{guest_socket_path}:1024"
  3. 文件系统挂载

    • rootfs 通过 pmem 设备挂载
    • 共享目录通过 virtiofs 挂载

第四阶段:监控和管理

  1. 进程监控

    rustCopy code1let sandbox_clone = sandbox_mutex.clone();
    2monitor(sandbox_clone);
    
  2. 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 容器运行时解决方案。

1.1.2 - 文件

启动 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

1.1.3 - cgroup

启动 Cloud Hypervisor 过程中的 cgroup 处理

内容来自 code wiki.


cgroup

问:当我在一个 bms 上创建多个 cloud hypervisor 的 microvm 时,cgroup 是如何设计的?什么时候创建 cgroup?

当在 bare-metal server (BMS) 上创建多个 Cloud Hypervisor microVM 时,Kuasar 会为每个 sandbox 设计和管理 cgroup,以实现资源隔离和控制。

Cgroup 的设计和创建时间

  1. Sandbox Cgroup 的创建:
    • KuasarSandboxer 收到创建 sandbox 的请求时,它会首先尝试为该 sandbox 创建 cgroup。
    • KuasarSandboxercreate 方法中 ( 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.rs create_mock_pod_sandbox_config 函数)。
    • 除了主 sandbox cgroup,还会创建两个子 cgroup:
      • vcpu cgroup (kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs),用于管理 vCPU 相关的 CPU 资源。
      • pod_overhead cgroup (kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs),用于管理 pod overhead 相关的 CPU 资源。
    • 创建时机: 这些 cgroup 在 KuasarSandboxer 处理 CreateSandbox 请求时,VM 启动之前被创建。
  2. 资源限制的应用:
    • 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 资源限制。
    • vcpupod_overhead cgroup 仅应用 CPU 资源限制 ( kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs )。
    • 应用时机: 资源限制在 sandbox cgroup 创建后立即应用,同样在 VM 启动之前。
  3. 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_overhead cgroup 中。
      • 将所有 vCPU 线程加入到 vcpu cgroup 中。
    • 加入时机: VMM 进程和 VCPU 线程在 MicroVM 启动并获取到其 PID 后,通过 add_to_cgroup 方法 ( kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs ) 加入到相应的 cgroup 中。
  4. 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 视图正确。
  5. Cgroup 的清理:
    • 当 sandbox 被删除时,KuasarSandboxer 会调用 sandbox_cgroups.remove_sandbox_cgroups ( kuasar-io/kuasar/vmm/sandbox/src/cgroup.rs ) 来清理所有相关的 cgroup。
    • 清理过程包括将 cgroup 中的任务移动到父 cgroup,然后删除子 cgroup 和主 cgroup。
    • 清理时机:KuasarSandboxerdelete 方法中 ( kuasar-io/kuasar/vmm/sandbox/src/sandbox.rs )。

总结:

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

1.1.4 - vmm task

启动 Cloud Hypervisor 过程中 vmm task 的启动方式

vmm task 启动

问:cloud hypervisor 的 microvm 里面的 kuasar agent,是通过什么方式启动的?systemd,还是 init 脚本?

在 Cloud Hypervisor MicroVM 内部,Kuasar agent (即 vmm-task) 是作为 PID 1 进程启动的,它会处理操作系统的初始化和信号,而不是通过传统的 systemdinit 脚本启动。

以下是 vmm-task 启动方式的详细说明:

  1. 作为 PID 1 启动:根据 [MicroVM Sandbox (VMM)](#microvm-sandbox-vmm) 和 VMM Task Lifecycle and Runtime Management 描述,vmm-task 在 Guest VM 内部作为 PID 1 进程运行。这意味着它是 Guest OS 启动后执行的第一个用户空间进程,负责管理容器和进程的生命周期,以及处理资源分配、网络配置和异步 I/O 操作。
  2. 初始化 VM 环境vmm-task 的主要入口点在 kuasar-io/kuasar/vmm/task/src/main.rs。这个组件会初始化 VM 的环境,设置必要的文件系统和内核参数。它还配置了一个 ttrpc 服务器,用于暴露服务以管理任务、沙箱和流,允许外部组件与 VM 的内部进程进行交互。
  3. 处理操作系统信号:作为 PID 1 进程,vmm-task 还负责处理操作系统信号,包括回收子进程和管理优雅关机,这在 kuasar-io/kuasar/vmm/task/src/main.rshandle_signals 函数中有体现。
  4. 配置通过内核命令行参数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