dbs结项报告

使用命令行参数启动微型虚拟机

1. 📽 项目实现方案研究:

实现方案给出是为了提供可复现性

配置描述
处理器AMD® Ryzen 7 4800h with radeon graphics × 16
内存32g
显卡NVIDIA Corporation TU117M [GeForce GTX 1650 Ti Mobile] / NVIDIA GeForce GTX 1650 Ti/PCIe/SSE2
OSUbuntu 22.04 LTS
rustc版本rustc 1.62.1

1.1 🎲 参考目标: firecracker

1.1.1 构建firecracker

cargo的使用文档: https://doc.rust-lang.org/cargo/index.html

如果需要编译其他平台的crate, 可能还需要用rustup添加对应的toolchain, rustup的使用文档: https://rust-lang.github.io/rustup/index.html

  1. 拉取源码:
1
2
git clone https://github.com/firecracker-microvm/firecracker
cd firecracker
  1. 配置依赖

    构建firecraker依赖于Docker, 我的个人博客上docker的安装笔记可供参考: Ubuntu上使用Docker

1
2
sudo apt install build-essential clang
cargo check
  1. 构建firecracker
1
2
3
4
tools/devtool build

# release
tools/devtool build --release

1.1.2 使用firecracker创建虚拟机

参考资料: https://github.com/firecracker-microvm/firecracker/blob/main/docs/getting-started.md

事实上, 报告的最终目的目的并不在于描述构建firecraker或者使用dbs之类的方式, 而是借助对firecraker的了解来辅助使用命令行参数从DBS中启动一个虚拟机, 因此文档叙述不以线性进行, 将进行跳转, 体现思考的过程.

​ 使用firecracker创建虚拟机, 需要这些内容:

  1. API socket
1
./firecracker --api-sock /tmp/firecracker.socket
  1. Linux kernel

  2. rootfs

​ 因此当我们开始了解DBS时, 需要关注DBS已经具备和不具备的要素,

1.2 🦌 更进一步

上面的步骤不存在任何困难, 但我们并不关心是否创建好虚拟机, 而关注在firecracker一开始是如何创建一个虚拟机

1.2.1 VMM的对外接口

定位到src/firecracker/src/main.rs, 关注在api-sock命令行参数

firecracker对虚拟机进行配置主要分为两种形式:

  1. HTTP API的请求方式进行配置(也可以同时指定配置文件)
  2. 通过指定配置文件的方式进行配置
1
2
3
4
5
6
7
8
9
10
11
12
rootfs_path=$(pwd)"/hello-rootfs.ext4"
curl --unix-socket /tmp/firecracker.socket -i \
-X PUT 'http://localhost/drives/rootfs' \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d "{
\"drive_id\": \"rootfs\",
\"path_on_host\": \"${rootfs_path}\",
\"is_root_device\": true,
\"is_read_only\": false
}"

1
2
# 不使用API进行配置, 传入配置文件
./firecracker --api-sock /tmp/firecracker.socket --config-file <path_to_the_configuration_file>

对于DBS而言, 项目最初目标是通过命令行参数进行启动, 而不需要kata的环境, 因此我们可以关注在使用配置文件创建虚拟机的代码逻辑部分, 因此可以关注函数run_without_api \rightarrow VmResources::from_json

1.2.2 rootfs和Linux kernel的使用方式

要了解rootfs和Linux kernel如何被使用了, 需要从main.rsrun_without_api中, 深入到build_microvm_from_json

  • kernel被以VmmConfig::block_devices的形式传入
  • rootfs作为VmmConfig::block_devices配置的一部分进行传入
  • 至于启动虚拟机等命令, 则可以HTTP API形式, 传递给api_server/src/lib.rs, 接受请求/actions的参数, 并启动配置好的虚拟机

至此, 我们可以带着疑问, 边开始实现我们的项目需求, 边浏览了解firecracker是如何实现的.

2. 🔨 阶段一: 创建命令行前端接口

由于rust编程经验不多, 因此尽可能使用第三方库, 在命令行解析上, 选用clap (Dual-licensed under Apache 2.0 or MIT, 对于DBS而言, 正好可以用Apache 2.0)

clap的使用文档: https://docs.rs/clap/latest/clap/

2.1 🍨 命令行配置项

kata-containersruntime-rs分支中, 可以在dragonball::vm::VmConfigInfo中看到DBS使用的虚拟机配置.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
pub struct CpuTopology {
/// threads per core to indicate hyperthreading is enabled or not
pub threads_per_core: u8,
/// cores per die to guide guest cpu topology init
pub cores_per_die: u8,
/// dies per socket to guide guest cpu topology
pub dies_per_socket: u8,
/// number of sockets
pub sockets: u8,
}

#[derive(Clone, Debug, PartialEq)]
pub struct VmConfigInfo {
/// Number of vcpu to start.
pub vcpu_count: u8,
/// Max number of vcpu can be added
pub max_vcpu_count: u8,
/// cpu power management.
pub cpu_pm: String,
/// cpu topology information
pub cpu_topology: CpuTopology,
/// vpmu support level
pub vpmu_feature: u8,

/// Memory type that can be either hugetlbfs or shmem, default is shmem
pub mem_type: String,
/// Memory file path
pub mem_file_path: String,
/// The memory size in MiB.
pub mem_size_mib: usize,

/// sock path
pub serial_path: Option<String>,
}

使用clap定义命令行参数后,具体内容如下:

argumentsrequireddefault valuedescription
rootfstrue-The path to rootfs image.
kernel-pathtrue-The path of kernel image (Only uncompressed kernel is supported for Dragonball).
log-filefalse"dbs-cli.log"The path to log file
log-levelfalse"Info"The logging level.
boot-argsfalseconsole=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda1The boot arguments passed to the kernel.
is-rootfalsetrueDecide the device to be the root boot device or not.
is-read-onlyfalsefalseThe driver opened in read-only or not.
vcpufalse1The number of vcpu to start.
max-vcpufalse1The max number of vpu can be added.
cpu-pmfalse0vpmu support level.
threads-per-corefalse1Threads per core to indicate hyper-threading is enabled or not.
cores-per-diefalse1Cores per die to guide guest cpu topology init.
dies-per-socketfalse1Dies per socket to guide guest cpu topology.
socketsfalse1The number of sockets.
mem-typefalseshmemMemory type that can be either hugetlbfs or shmem.
mem-filefalse``Memory file path.
initrd-pathfalseNoneThe path of initrd.

2.2 参数相关的注意事项:

整个命令行参数最为关键的三个参数是rootfs, kernel-pathboot-args. 由于从命令行终端进入vm的console采用的方式是将ttySx的输出重定向到当前终端的stdout, 因此需要确保kernel支持serial console并且rootfs在构建时需要配置好启动之后能够启动对应终端, 否则将无法进入vm. 对于boot-args, console=xxroot="dev/vda1" 是根据对应rootfs的设置来的, 因此虽然不是必须给出的参数, 但是需要自行查看是否需要有所修改。

3. 🔥 阶段二: 项目实现思路及问题解决

3.1 命令行参数:

​ 根据firecraker和kata-container现有代码,确定启动虚拟机必备参数后,便可直接用clap提供的一些derive来定义命令行参数,参数项见上表,暂无问题出现。

3.2 进入vm终端:

​ 基于现有kata-container的一些创建vm、启动vm、创建设备等API,只需进行简单的修改调用即可完成。但是最后在IO上出现问题,具体可以描述为创建vm的标准输入输出终端时,com1未将输出重定向到stdout,导致无法与vm进行交互。

​ 解决方法,为com1设置输出流并重定向到stdout

1
device.lock().unwrap().set_output_stream(Some(Box::new(std::io::stdout())));

3.3 基本原理: serial console

下图为串口对应终端名以及IO地址

kata-containerruntime-rs分支下,com2被用来输出日志信息(同时也将dmesg也写入logger了),因此只能使用设备com1连接到对应的终端。

console=device,options 用来指定终端的输出,该参数放在kernel的启动参数中。

device可能的值为:

1
2
3
4
5
tty0 for the foreground virtual console
ttyX for any other virtual console
ttySx for a serial port
lp0 for the first parallel port
ttyUSB0 for the first USB serial device

kata-container仓库runtime-rs分支的现有代码下,已经有通过socket进入serial console的代码,但是从命令行将stdio重定向到虚拟机serial console的代码却不能达到正常预期。在通过反复浏览代码,通过3.2中的修改,解决了无法创建stdio console的问题,再加上此前实现的命令行参数解析,整个流程就已经完成了。

4. 项目成果展示:

4.1 本地开发仓库:

仓库地址: https://github.com/QiliangFan/kata-containers

分支:runtime-rs

4.2 pull request:

4.3 运行示例与结果截图:

为了结果易于复现,使用了firecraker项目的kernel和rootfs(方便用户下载, 当然其他支持serial console的内核和rootfs也可以),如需运行此CLI,可前往firecracker/getting-started.md at main · firecracker-microvm/firecracker (github.com)下载并使用

1
./dbs-cli --kernel-path ~/data/build/dbs/firecracker/vmlinux.bin --rootfs ~/data/build/dbs/firecracker/bionic.rootfs.ext4 --boot-args "console=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda"

进入vm

输入指令

4.4 可通过命令行配置的参数:

argumentsrequireddefault valuedescription
rootfstrue-The path to rootfs image.
kernel-pathtrue-The path of kernel image (Only uncompressed kernel is supported for Dragonball).
log-filefalse"dbs-cli.log"The path to log file
log-levelfalse"Info"The logging level.
boot-argsfalseconsole=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda1The boot arguments passed to the kernel.
is-rootfalsetrueDecide the device to be the root boot device or not.
is-read-onlyfalsefalseThe driver opened in read-only or not.
vcpufalse1The number of vcpu to start.
max-vcpufalse1The max number of vpu can be added.
cpu-pmfalse0vpmu support level.
threads-per-corefalse1Threads per core to indicate hyper-threading is enabled or not.
cores-per-diefalse1Cores per die to guide guest cpu topology init.
dies-per-socketfalse1Dies per socket to guide guest cpu topology.
socketsfalse1The number of sockets.
mem-typefalseshmemMemory type that can be either hugetlbfs or shmem.
mem-filefalse``Memory file path.
initrd-pathfalseNoneThe path of initrd.

4.5 使用示例:

1
2
3
4
./dbs-cli \
--kernel-path ~/data/build/dbs/vmlinux.bin \
--rootfs ~/data/build/dbs/rootfs.dmg \
--boot-args "console=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda1" ;

For the rootfs from firecracker:

1
2
3
4
./dbs-cli \
--kernel-path ~/data/build/dbs/vmlinux.bin \
--rootfs ~/data/build/dbs/bionic.rootfs.ext4 \
--boot-args "console=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda" ;

For the rootfs build from kata:

1
2
3
4
./dbs-cli \
--kernel-path ~/data/build/dbs/vmlinux.bin \
--rootfs ~/data/build/dbs/kata-containers.img \
--boot-args "console=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda1" ;

Set the log level and log file:

The log-level argument is case-insensitive: ErrOR and InFO are valid.

1
2
3
4
5
./dbs-cli \
--log-file dbs-cli.log --log-level ERROR \
--kernel-path ~/data/build/dbs/vmlinux.bin \
--rootfs ~/data/build/dbs/kata-containers.img \
--boot-args "console=ttyS0 tty0 reboot=k debug panic=1 pci=off root=/dev/vda1" ;

dbs结项报告
https://www.torch-fan.site/2022/09/03/dbs结项报告/
作者
Torch-Fan
发布于
2022年9月3日
更新于
2022年11月15日
许可协议