# StratoVirt 启动准备 StratoVirt提供了轻量虚拟机和标准虚拟机两种机型。两种机型的启动过程如下。 ## 轻量虚拟机启动过程 ### 1. 构建内核镜像 StratoVirt的轻量虚拟机机型在x86_64平台上支持PE格式或是bzImage格式的内核镜像,在 aarch64平台上支持PE格式的内核镜像。通过以下步骤来构建内核镜像: 1. 首先,获取openEuler内核源码: ```shell $ git clone -b kernel-5.10 --depth=1 https://gitee.com/openeuler/kernel $ cd kernel ``` 如果你安装我们openEuler的21.03版本,也可以通过使用yum源的方式来获取内核源码: ```shell $ sudo yum install kernel-source $ cd /usr/src/linux-5.10.0-0.0.0.7.oe1.$(uname -m)/ ``` 2. 配置linux内核信息。你可以使用 [我们提供的轻量虚拟机内核配置文件](./kernel_config/micro_vm) 并且将配置文件重命名为`.config`拷贝至`kernel`路径下。 当然你也可以通过命令修改内 核编译选项: ```shell $ make menuconfig ``` 3. 构建并将内核镜像转换为PE格式。 ```shell $ make -j$(nproc) vmlinux && objcopy -O binary vmlinux vmlinux.bin ``` 4. 如果你想要在x86_64平台编译bzImage格式内核镜像。 ```shell $ make -j$(nproc) bzImage ``` ### 2. 构建rootfs镜像 Rootfs镜像是一种文件系统镜像。在StratoVirt启动时可以挂载带有`/sbin/init`的EXT4格 式镜像。你可以查看[附录](#2附录)。 ### 3. 启动命令样例 ```shell /usr/bin/stratovirt \ -machine microvm \ -kernel /path/to/kernel \ -smp 1 \ -m 1024m \ -append "console=ttyS0 pci=off reboot=k quiet panic=1 root=/dev/vda" \ -drive file=/path/to/rootfs,id=rootfs,readonly=off,direct=off \ -device virtio-blk-device,drive=rootfs,id=rootfs \ -qmp unix:/path/to/socket,server,nowait \ -serial stdio ``` ## 标准虚拟机启动过程 标准虚拟机有两种启动方式,第一种使用kernel+rootfs;另一种是使用预先安装好guest 操 作系统的raw格式镜像。 接下来讲解如何通过以上所述的两种方式启动标准虚拟机。以上两种启动方式均需使用标准启动 固件,为此首先讲解如何获取标准启动固件。 ### 1. 获取标准启动固件 标准启动需要启动固件。Stratovirt仅支持在x86_64和aarch64平台上从UEFI(统一可扩展 固件接口)启动。 EDK2是一个实现了UEFI规范的开源项目。我们使用EDK2作为固件启动虚拟机,因此我们必须 获得相应的EDK2二进制文件. 有两种方法可以获取EDK2二进制文件,通过yum源直接安装或从源代码编译。具体步骤如下。 请注意,EDK2二进制文件包含两个文件,一个用于存储可执行代码,另一个用于存储引导数据。 #### 1.1 直接安装EDK2 在x86_64平台, 运行 ```shell $ sudo yum install -y edk2-ovmf ``` 在aarch64平台, 运行 ```shell $ sudo yum install -y edk2-aarch64 ``` 安装edk2之后,在x86_64平台, `OVMF_CODE.fd` 和 `OVMF_VARS.fd` 文件存在于 `/usr/share/edk2/ovmf` 目录下。 在aarch64平台, `QEMU_EFI-pflash.raw` 和 `vars-template-pflash.raw` 文件会存在于`/usr/share/edk2/aarch64` 目录下。 #### 1.2 从源代码编译 ```shell # 安装必要依赖包用于编译edk2。 yum install git nasm acpica-tools -y # 克隆 edk2 源代码. git clone https://github.com/tianocore/edk2.git cd edk2 git checkout edk2-stable202102 git submodule update --init # 编译 edk2, 并获取固件文件用于启动StratoVirt。 arch=`uname -m` if [ ${arch} = "x86_64" ]; then echo "ACTIVE_PLATFORM = OvmfPkg/OvmfPkgX64.dsc" >> Conf/target.txt echo "TARGET_ARCH = X64" >> Conf/target.txt elif [ ${arch} = "aarch64" ]; then echo "ACTIVE_PLATFORM = ArmVirtPkg/ArmVirtQemu.dsc" >> Conf/target.txt echo "TARGET_ARCH = AARCH64" >> Conf/target.txt else echo "${arch} architecture not supported." exit 1 fi echo "TOOL_CHAIN_TAG = GCC5" >> Conf/target.txt echo "BUILD_RULE_CONF = Conf/build_rule.txt" >> Conf/target.txt echo "TARGET = RELEASE" >> Conf/target.txt make -C BaseTools . ./edksetup.sh build if [ ${arch} = "x86_64" ]; then cp ./Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd /home/ cp ./Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd /home/ elif [ ${arch} = "aarch64" ]; then dd if=/dev/zero of=/home/STRATOVIRT_EFI.raw bs=1M count=64 dd of=/home/STRATOVIRT_EFI.raw if=./Build/ArmVirtQemu-AARCH64/RELEASE_GCC5/FV/QEMU_EFI.fd conv=notrunc dd if=/dev/zero of=/home/STRATOVIRT_VAR.raw bs=1M count=64 fi ``` 编译edk2之后,在x86_64平台, `OVMF_CODE.fd` 和 `OVMF_VARS.fd` 文件会位于 `/home` 目录下。在aarch64平台, `STRATOVIRT_EFI.raw` 和 `STRATOVIRT_VAR.raw` 文件会位于 `/home` 目录下. ### 2. 以 kernel + rootfs 方式启动标准虚拟机 #### 2.1 构建内核镜像 StratoVirt的标准虚拟机机型支持x86_64平台的bzImage格式内核镜像和aarch64平台的PE格 式内核镜像。内核镜像构建如下: 1. 获取openEuler内核源码: ```shell $ git clone -b kernel-5.10 --depth=1 https://gitee.com/openeuler/kernel $ cd kernel ``` 2. 配置linux内核信息。你可以使用我们提供的标准虚拟机 [内核配置文件](./kernel_config/standard_vm) 并且将配置文件重命名为`.config`拷贝至`kernel`路径下。 3. 构建内核镜像 ```shell # 在aarch64平台,将内核镜像转换为PE格式。 $ make -j$(nproc) vmlinux && objcopy -O binary vmlinux vmlinux.bin # 在x86_64平台,将内核镜像转换为bzImage格式. $ make -j$(nproc) bzImage ``` 除了手动构建内核镜像的方式以外,也可以直接从 openEuler 官网下载对应的 [内核镜像](https://repo.openeuler.org/openEuler-21.09/stratovirt_img/x86_64/std-vmlinuxz)。 #### 2.2 构建rootfs镜像 为标准虚拟机构建rootfs镜像实际上与轻量虚拟机相同。你可以通过[附录](#2附录)查看更多 的详细信息。 ### 3. 以 raw 格式镜像启动标准虚拟机 #### 3.1 获取 raw 格式镜像 你可以从 openEuler 官网下载已经安装好的 [qcow2 镜像](https://repo.openeuler.org/openEuler-21.03/virtual_machine_img/x86_64/openEuler-21.03-x86_64.qcow2.xz)。 下载之后,可以利用 qemu-img 命令进行转换。接下来以 openEuler-21.03 版本的 qcow2 镜像为例给出具体命令: ```shell $ xz -d openEuler-21.03-x86_64.qcow2.xz $ qemu-img convert -f qcow2 -O raw openEuler-21.03-x86_64.qcow2 openEuler-21.03-x86_64.raw ``` 至此就获得了可以使用的 raw 格式镜像。 ### 4. 以 direct kernel boot 方式启动标准虚拟机 为virt虚机主板提供直接从kernel启动的模式。在该模式下,不需要UEFI和APCI表, 虚拟机将跳过UEFI启动阶段,直接从kernel启动,从而加快启动速度。 启动命令行如下: ```shell /usr/bin/stratovirt \ -machine virt \ -kernel /path/to/kernel \ -smp 1 \ -m 2G \ -append "console=${con} reboot=k panic=1 root=/dev/vda rw" \ -drive file=/path/to/rootfs,id=rootfs,readonly=off,direct=off \ -device virtio-blk-pci,drive=rootfs,id=blk1,bus=pcie.0,addr=0x2 \ -qmp unix:/path/to/socket,server,nowait \ -serial stdio ``` 说明:当前只支持ARM架构下virt虚机主板快速启动标准虚拟机。 ### 5. 启动命令行样例 请注意,标准虚拟机需要两个PFlash设备,它们将使用来自与EDK2二进制的两个固件文件。 如果你不需要保持启动信息,单元序列为1的数据存储文件可以被省略。但是单元序号为0的 代码存储文件是必须的。 首先给出 kernel + rootfs 的启动命令,具体如下: ```shell arch=`uname -m` if [ ${arch} = "x86_64" ]; then con=ttyS0 machine="q35" elif [ ${arch} = "aarch64" ]; then con=ttyAMA0 machine="virt" else echo "${arch} architecture not supported." exit 1 fi /usr/bin/stratovirt \ -machine ${machine} \ -kernel /path/to/kernel \ -smp 1 \ -m 2G \ -append "console=${con} reboot=k panic=1 root=/dev/vda rw" \ -drive file=/path/to/rootfs,id=rootfs,readonly=off,direct=off \ -device virtio-blk-pci,drive=rootfs,id=blk1,bus=pcie.0,addr=0x2 \ -drive file=/path/to/OVMF_CODE.fd,if=pflash,unit=0,readonly=true \ -drive file=/path/to/OVMF_VARS.fd,if=pflash,unit=1 \ -qmp unix:/path/to/socket,server,nowait \ -serial stdio ``` 最后给出 raw 格式镜像的启动命令,具体如下: ```shell /usr/bin/stratovirt \ -machine ${machine} \ -smp 1 \ -m 2G \ -drive file=/path/to/raw_image,id=raw_image,readonly=off,direct=off \ -device virtio-blk-pci,drive=raw_image,id=blk1,bus=pcie.0,addr=0x2 \ -drive file=/path/to/OVMF_CODE.fd,if=pflash,unit=0,readonly=true \ -drive file=/path/to/OVMF_VARS.fd,if=pflash,unit=1 \ -qmp unix:/path/to/socket,server,nowait \ -serial stdio ``` ## 附录 以下是一种制作EXT4格式rootfs镜像的方法: 1. 准备一个合适大小的文件(例如 1G): ```shell $ dd if=/dev/zero of=./rootfs.ext4 bs=1G count=20 ``` 2. 在这个文件上创建一个空的EXT4格式的文件系统: ```shell $ mkfs.ext4 ./rootfs.ext4 ``` 3. 挂载文件系统镜像: ```shell $ mkdir -p /mnt/rootfs $ sudo mount ./rootfs.ext4 /mnt/rootfs && cd /mnt/rootfs ``` 4. 获取 [最新的alpine-minirootfs](http://dl-cdn.alpinelinux.org/alpine) : ```shell $ arch=`uname -m` $ wget http://dl-cdn.alpinelinux.org/alpine/v3.13/releases/$arch/alpine-minirootfs-3.13.0-$arch.tar.gz -O alpine-minirootfs.tar.gz $ tar -zxvf alpine-minirootfs.tar.gz $ rm alpine-minirootfs.tar.gz ``` 为EXT4格式文件系统镜像制作一个简单的 `/sbin/init` 。 ```shell $ rm sbin/init && touch sbin/init && cat > sbin/init <<EOF #! /bin/sh mount -t devtmpfs dev /dev mount -t proc proc /proc mount -t sysfs sysfs /sys ip link set up dev lo exec /sbin/getty -n -l /bin/sh 115200 /dev/ttyS0 poweroff -f EOF $ sudo chmod +x sbin/init ``` **注意: alpine仅是一个例子。你可以使用任何开源的拥有init/systemd的rootfs文件系统来制作rootfs镜像。** 5. 卸载rootfs镜像: ```shell $ cd ~ && umount /mnt/rootfs ``` ## 链接 - [EDK2的wiki](https://github.com/tianocore/tianocore.github.io/wiki/EDK-II) - [OVMF的wiki](https://github.com/tianocore/tianocore.github.io/wiki/OVMF)