鲲鹏轻量级虚拟化实验(华为云ECS版)

实验简介

实验介绍

本实验介绍在华为鲲鹏平台上安装鲲鹏轻量级虚拟化软件 StratoVirt,并在此之上配置虚拟机、管理虚拟机生命周期、管理虚拟机资源,以及了解如何对接 iSula 安全容器。

与最初基于物理服务器的版本相比,本版面向华为公有云 ECS 编写。公有云 ECS 默认不开放嵌套虚拟化(Guest 内部没有 /dev/kvm),而 StratoVirt 只支持 KVM 加速,因此 StratoVirt 无法直接在 ECS 内启动虚拟机。本实验的处理方式是:

  • 保留 StratoVirt 的安装、KVM 能力检查、镜像准备等全部内容;
  • 使用 QEMU + TCG(纯软件模拟) 承载 openEuler 官方 StratoVirt 演示镜像,启动同一台 openEuler 虚拟机;
  • 使用 QMP(QEMU Machine Protocol) 完成生命周期、热插拔、Balloon、内存快照等全部管理练习。QMP 是 StratoVirt 与 QEMU 共同支持的管理接口,命令语义基本一致,差异点在文中逐条标注。

这样既不动摇"轻量级虚拟化 + QMP 管理"的核心技能,也能让学生在一个真实的公有云环境中完整走通实验,并理解"嵌套虚拟化"这一云上常见限制。

与物理服务器版本的差异(先读)

项目物理服务器版本华为云 ECS 版本(本手册)
虚拟化加速KVM(/dev/kvm 可用)无 KVM,改用 QEMU/TCG 纯软件模拟
启动程序stratovirtqemu-system-aarch64
管理接口StratoVirt QMPQEMU QMP(需先执行 qmp_capabilities 握手)
设备模型virtio-mmio(microvm)virtio-pci(标准机 virt)
镜像手工编译内核 + Alpine rootfs官方 std-vmlinux.bin + openEuler 镜像
性能接近原生明显变慢,仅用于功能验证

说明:本手册任务一~任务六的主干命令与回显,均在华为云 ECS(openEuler 22.03 LTS,aarch64,8 vCPU)上实际验证通过。任务七的 iSulad 安装与配置可参照执行,安全容器运行部分受 KVM 限制,未在公有云 ECS 上验证。

建议课时

本实验建议安排 2.5~3 学时:任务一~任务三约 60 分钟(含镜像下载),任务四~任务六约 60 分钟,任务七(选做)约 30 分钟。

预备知识

学习本实验需要掌握基本的 Linux 操作系统操作命令,了解 SSH 登录、软件包安装、磁盘与进程的基本操作。

实验目的

  • 理解 StratoVirt 的架构、原理,以及它对 KVM 的依赖。
  • 掌握 StratoVirt 的安装与虚拟化能力检查。
  • 掌握在公有云 ECS 上准备镜像并启动轻量级虚拟机。
  • 掌握通过 QMP 管理虚拟机的生命周期、磁盘/网卡热插拔、内存 Balloon 与内存快照。
  • 了解 StratoVirt 对接 iSula 安全容器(Kata Containers)的原理与配置。

实验环境

云主机(华为云 ECS)要求:

项目要求
架构AArch64(鲲鹏,不能选 x86 规格)
规格建议 8 vCPU / 16 GiB 及以上(最低 4 vCPU / 8 GiB)
系统盘80 GiB 及以上
操作系统openEuler 22.03 LTS(aarch64)
网络绑定弹性公网 IP,安全组放通 TCP 22
登录方式SSH,root 用户

嵌套虚拟机配置:

类型要求
数量1
操作系统openEuler 22.03 LTS(aarch64)
vCPU4 核(最大可扩展 8 核)
内存4 GiB
磁盘官方镜像约 1.2 GiB(实验另加 512 MiB 数据盘)

实验软件:

软件用途获取方式
stratovirt轻量级虚拟化软件yum install stratovirt
qemu-system-aarch64本实验的虚拟机运行载体(TCG)yum install qemu-system-aarch64
nmap(含 ncat)连接 QMP 管理通道yum install nmap
socat连接虚拟机串口控制台yum install socat
openEuler 官方镜像内核与根盘openEuler 镜像站
MobaXterm / 终端SSH 登录 ECS官网下载

实验架构

┌──────────────────────────── 华为云 ECS(aarch64,openEuler 22.03)────────────────────────────┐
│                                                                                              │
│   ┌─────────────┐   QMP(unix socket)   ┌──────────────────────────────────────────────┐     │
│   │  ncat 终端   │◄────────────────────►│  qemu-system-aarch64(TCG 模拟,替代 StratoVirt)│     │
│   └─────────────┘                      │   ├─ 内存:4 GiB(virtio-balloon 可调)         │     │
│                                        │   ├─ 磁盘:openEuler 官方镜像(virtio-blk)     │     │
│   ┌─────────────┐   串口 console.sock   │   ├─ 网卡:virtio-net(可热插拔)                │     │
│   │ socat 终端   │◄────────────────────►│   └─ QMP:/tmp/qmp1.socket                      │     │
│   └─────────────┘                      └───────────────────┬──────────────────────────┘     │
│                                                             │                                │
│                                                    ┌────────▼────────┐                       │
│                                                    │ openEuler 22.03 │                       │
│                                                    │ 嵌套虚拟机       │                       │
│                                                    └─────────────────┘                       │
└──────────────────────────────────────────────────────────────────────────────────────────────┘

任务零:开通并初始化华为云 ECS

步骤1 购买 ECS

在华为云控制台购买一台 ECS,关键选项如下:

配置项选择
计费模式按需计费(实验结束及时释放)
区域就近选择
规格鲲鹏通用计算型 kc1(如 8 vCPU / 16 GiB)
镜像公共镜像 → openEuler → openEuler 22.03 LTS(aarch64)
系统盘80 GiB 高 IO
网络默认 VPC,自动分配
弹性公网 IP现在购买,按带宽计费(5 Mbit/s 足够)
安全组放通 TCP 22(SSH)
登录凭证密码(本实验使用 root 登录)

提示:实验只需一台 ECS。若预算有限,4 vCPU / 8 GiB 也可以完成,但 TCG 模式下启动和操作会明显变慢。

步骤2 登录 ECS

在本地终端(Windows 可用 MobaXterm 或 PowerShell 自带的 ssh)执行:

ssh root@<ECS 弹性公网 IP>

首次登录输入 yes,再输入购买时设置的密码。

步骤3 检查环境

uname -m                 # 应输出 aarch64
cat /etc/os-release      # 应为 openEuler 22.03 LTS
nproc                    # CPU 核数
free -h                  # 内存
df -h /                  # 系统盘剩余空间

预期结果:

aarch64
NAME="openEuler"
VERSION="22.03 LTS"
...

步骤4 检查软件源

华为云 openEuler 镜像默认已配置华为云 repo:

cat /etc/yum.repos.d/openEuler.repo | grep baseurl

若后续安装软件时出现 GPG 校验失败(公有云镜像常见),在命令后追加 --nogpgcheck 临时跳过校验即可,例如:

yum install -y stratovirt --nogpgcheck

注意:--nogpgcheck 仅用于实验环境绕过镜像源签名问题,生产环境不建议长期使用。


任务一:安装 StratoVirt 并验证虚拟化能力

本任务完成 StratoVirt 的安装,并学会判断一台云主机是否具备运行 StratoVirt 的条件。这是本实验在云上最重要的一个认知环节。

步骤1 安装 StratoVirt

yum install -y stratovirt --nogpgcheck

查看版本:

stratovirt -version

预期输出:

StratoVirt 2.1.0

步骤2 检查 KVM 设备

StratoVirt 是基于 KVM 的轻量级虚拟化软件,运行前必须存在 /dev/kvm 设备:

ls -l /dev/kvm

在华为云 ECS 上,预期输出为:

ls: cannot access '/dev/kvm': No such file or directory

步骤3 查看内核虚拟化初始化信息

dmesg | grep -i 'HYP mode'

预期输出:

[    1.217066] kvm [1]: HYP mode not available

HYP mode not available 表示当前 ECS 自身运行在 KVM 虚拟机中,宿主机没有向它暴露 ARM 的 EL2(Hypervisor)异常级别,因此 ECS 内部不能再创建 KVM 虚拟机。这就是公有云上"不支持嵌套虚拟化"的直接表现。

步骤4 结论与实验方案

  • StratoVirt 只支持 -accel kvm,没有 TCG 软件模拟后端,因此在没有 /dev/kvm 的 ECS 上无法启动。
  • 本实验后续改用 QEMU 的 TCG 模式运行同一套 openEuler 官方 StratoVirt 镜像,并使用 QMP 完成全部管理练习。
  • 如果后续拿到支持嵌套虚拟化的环境(裸金属服务器、支持嵌套虚拟化的规格),可以无缝切回 StratoVirt,命令见附录 D。

本步骤的验证实验在任务二下载完镜像后进行(需要内核和根盘才能看到 StratoVirt 的真实报错)。


任务二:准备虚拟机镜像

步骤1 安装运行环境

yum install -y qemu-system-aarch64 nmap socat --nogpgcheck
  • qemu-system-aarch64:本实验的虚拟机运行载体。
  • nmap:提供 ncat,用于连接 QMP 管理通道。
  • socat:用于连接虚拟机串口控制台。

检查:

qemu-system-aarch64 --version | head -1
which ncat socat

预期输出类似:

QEMU emulator version 6.2.0 (qemu-6.2.0-88.oe2203)
/usr/bin/ncat
/usr/bin/socat

步骤2 下载 openEuler 官方镜像

StratoVirt 官方在 openEuler 22.03 LTS 镜像目录中提供了配套的内核与根盘。本实验使用 标准机(virt) 版本,因此内核必须使用 std-vmlinux.bin。

mkdir -p /opt/vm
cd /opt/vm
BASE=https://dl-cdn.openeuler.openatom.cn/openEuler-22.03-LTS/stratovirt_img/aarch64

wget $BASE/std-vmlinux.bin
wget $BASE/openEuler-22.03-LTS-stratovirt-aarch64.img.xz
wget $BASE/std-vmlinux.bin.sha256sum
wget $BASE/openEuler-22.03-LTS-stratovirt-aarch64.img.xz.sha256sum

如果 dl-cdn 地址访问慢,可换成 https://repo.openeuler.org/openEuler-22.03-LTS/stratovirt_img/aarch64/,内容相同。

步骤3 校验并解压

cd /opt/vm
sha256sum -c std-vmlinux.bin.sha256sum
sha256sum -c openEuler-22.03-LTS-stratovirt-aarch64.img.xz.sha256sum
xz -dk openEuler-22.03-LTS-stratovirt-aarch64.img.xz
ls -lh

预期结果:

std-vmlinux.bin: OK
openEuler-22.03-LTS-stratovirt-aarch64.img.xz: OK
...
-rw-r--r-- 1 root root 1.2G ... openEuler-22.03-LTS-stratovirt-aarch64.img
-rw-r--r-- 1 root root  24M ... std-vmlinux.bin

步骤4 认识两个内核(关键)

镜像目录下有两个内核文件,选错内核是本实验最常见的启动失败原因:

文件大小适用机器类型设备模型能否配标准镜像启动
vmlinux.bin约 10.3 MiBmicrovmvirtio-mmio不能:没有 virtio-blk-pci,会出现 VFS: Cannot open root device "vda" 内核 panic
std-vmlinux.bin约 23.7 MiB标准机 virtvirtio-pci可以

本实验使用标准机 virt + std-vmlinux.bin + 官方根盘。若使用 microvm,需要配套的 microvm 内核和 virtio-blk-device 设备模型,不能直接套用本文的 root=/dev/vda 配置。

步骤5 验证 StratoVirt 在本机无法启动(理解 KVM 依赖)

下载完镜像后,可以亲眼看到 StratoVirt 在无 KVM 环境下的真实报错:

stratovirt -machine virt -accel kvm \
  -kernel /opt/vm/std-vmlinux.bin \
  -append "root=/dev/vda console=ttyAMA0 rw" \
  -drive file=/opt/vm/openEuler-22.03-LTS-stratovirt-aarch64.img,id=rootfs \
  -m 2G -smp 2 \
  -qmp unix:/tmp/sv.qmp,server,nowait -D /tmp/sv.log -nographic

cat /tmp/sv.log

预期输出(关键行):

ERROR: Failed to open /dev/kvm: No such file or directory (os error 2)

这说明 StratoVirt 已经安装成功,但缺少 KVM 设备无法运行。后续任务改用 QEMU/TCG 完成。

步骤6(拓展,选做)手工编译内核与制作 rootfs

本节仅用于理解原理,不要求完成。公有云 ECS 上编译内核耗时长,且手工镜像容易出现驱动缺失、串口配置错误等问题,实验统一使用官方镜像。

编译内核(了解):

yum install -y git flex bison elfutils-libelf-devel dwarves bc openssl-devel \
               ncurses-devel rpm-build --nogpgcheck
yum groupinstall -y "Development Tools" --nogpgcheck

cd /root
git clone https://gitee.com/openeuler/kernel
cd kernel
git checkout openEuler-22.03-LTS

# 使用 StratoVirt 提供的 microvm 内核配置
cp ~/stratovirt-master/docs/kernel_config/kernel_config_5.10_aarch64 /root/kernel/kernel510.config
make olddefconfig
make -j"$(nproc)" vmlinux
objcopy -O binary vmlinux vmlinux.bin

注意事项:

  • 编译产物是 microvm 内核,只能配合 microvm 机器类型和 virtio-mmio 设备使用。
  • 编译时间较长(ECS 上可能 30 分钟以上),可跳过。
  • 若使用本手册的标准机配置,请直接使用官方 std-vmlinux.bin。

制作 rootfs(了解):

cd /home
dd if=/dev/zero of=./rootfs.ext4 bs=1G count=10
mkfs.ext4 ./rootfs.ext4
mkdir -p /mnt/rootfs
mount ./rootfs.ext4 /mnt/rootfs && cd /mnt/rootfs

wget http://dl-cdn.alpinelinux.org/alpine/latest-stable/releases/aarch64/alpine-minirootfs-3.16.0-aarch64.tar.gz
tar -zxvf alpine-minirootfs-3.16.0-aarch64.tar.gz
rm alpine-minirootfs-3.16.0-aarch64.tar.gz

若 ECS 无法访问 alpine 官网,可由教师提供 alpine-minirootfs-3.16.0-aarch64.tar.gz,用 scp 上传到 /mnt/rootfs 后再解压。

为镜像制作一个简单的 /sbin/init。注意:此时当前目录是挂载点,但 /sbin/init 是宿主机的绝对路径,必须写成 $ROOT/sbin/init,否则会破坏 ECS 自身的 init!

ROOT=/mnt/rootfs
rm -f "$ROOT/sbin/init"
cat > "$ROOT/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/ttyAMA0
EOF
chmod +x "$ROOT/sbin/init"
cd /
umount /mnt/rootfs

注意:

  • 标准机 virt 的串口是 ttyAMA0,不是 ttyS0;写错会看不到登录提示符。
  • 不要在 init 末尾直接写 poweroff -f,否则串口会话结束会立刻关机。
  • 手工 rootfs 的驱动、串口配置与官方内核不一定匹配,容易启动失败;实验仍以官方镜像为准。

步骤7(了解)标准启动所需固件

StratoVirt 在 aarch64 上支持 UEFI 标准启动,需要 EDK II 固件:

yum install -y edk2-aarch64 --nogpgcheck
ls /usr/share/edk2/aarch64/

本实验使用 -kernel 直接引导内核,不经过 UEFI 固件,因此该步骤只作了解。


任务三:启动第一台虚拟机

步骤1 创建启动脚本

cat > /opt/vm/start-vm.sh <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
VM_DIR=/opt/vm

# 防止重复启动(两个实例同时写一块磁盘会损坏镜像)
if [ -f "$VM_DIR/qemu.pid" ] && kill -0 "$(cat "$VM_DIR/qemu.pid")" 2>/dev/null; then
  echo "VM already running (pid $(cat "$VM_DIR/qemu.pid"))"
  exit 1
fi

rm -f /tmp/qmp1.socket "$VM_DIR/console.sock"

qemu-system-aarch64 \
  -machine virt,gic-version=3 \
  -accel tcg,thread=multi -cpu cortex-a72 \
  -smp 4,maxcpus=8 -m 4G \
  -kernel "$VM_DIR/std-vmlinux.bin" \
  -append "root=/dev/vda console=ttyAMA0 rw reboot=k panic=1" \
  -drive file="$VM_DIR/openEuler-22.03-LTS-stratovirt-aarch64.img",if=virtio,format=raw \
  -device virtio-balloon-pci,id=balloon0 \
  -device pcie-root-port,id=rp1,chassis=1,slot=1 \
  -device pcie-root-port,id=rp2,chassis=2,slot=2 \
  -display none \
  -qmp unix:/tmp/qmp1.socket,server=on,wait=off \
  -chardev socket,id=con0,path="$VM_DIR/console.sock",server=on,wait=off,logfile="$VM_DIR/console.log",logappend=on \
  -serial chardev:con0 \
  -pidfile "$VM_DIR/qemu.pid" -daemonize

echo "VM started, pid $(cat "$VM_DIR/qemu.pid")"
EOF
chmod +x /opt/vm/start-vm.sh

步骤2 启动虚拟机

/opt/vm/start-vm.sh

查看进程和串口日志:

ps -p "$(cat /opt/vm/qemu.pid)" -o pid,etime,pcpu,pmem,comm
tail -f /opt/vm/console.log

TCG 为纯软件模拟,启动到登录提示约需 15~30 秒。看到如下内容即启动成功:

openEuler 22.03 LTS
Kernel 5.10.0 on an aarch64

StratoVirt login:

按 Ctrl+C 退出 tail。

步骤3 登录虚拟机

新开一个 SSH 终端(保持虚拟机运行),执行:

socat -,raw,echo=0 unix-connect:/opt/vm/console.sock

出现登录提示后输入:

用户名:root
密码:openEuler12#$

登录成功后会看到:

[root@StratoVirt ~]#

在这里插入图片描述

断开控制台:按 Ctrl+C(只断开 socat,不会关闭虚拟机)。再次执行 socat 命令可重新接入。

步骤4 启动参数说明

参数作用说明
-machine virt,gic-version=3标准机机型aarch64 的标准机;对应 StratoVirt 的 -machine virt
-accel tcg,thread=multi软件模拟加速器无 KVM 时的替代方案
-cpu cortex-a72模拟 CPU 型号鲲鹏平台通用
-smp 4,maxcpus=84 个在线 vCPU,最多可扩展到 8 个便于观察 offline vCPU
-m 4G内存 4 GiBBalloon 实验使用
-kernel std-vmlinux.bin标准机内核必须用 std 内核
-append ...内核命令行串口 ttyAMA0、根盘 /dev/vda
-drive ...,if=virtio根盘virtio-blk-pci 设备
-device virtio-balloon-pci内存气球设备任务五使用
-device pcie-root-port ×2PCIe 根端口热插拔磁盘/网卡必须挂到根端口上
-qmp unix:/tmp/qmp1.socketQMP 管理通道任务四使用
-chardev socket... + -serial串口控制台通过 socat 接入
-daemonize后台运行断开 SSH 不影响虚拟机

步骤5 常见启动问题

现象原因处理
Kernel panic ... VFS: Cannot open root device "vda"使用了 microvm 内核 vmlinux.bin改用 std-vmlinux.bin
启动后没有任何输出串口参数写成 ttyS0,或没有接入 console.sock内核命令行用 ttyAMA0,用 socat 接入
qemu-system-aarch64: -drive ... Could not open镜像路径错误或未解压检查 /opt/vm 下文件
启动非常慢TCG 软件模拟正常现象;可减小 -smp/-m,但功能验证建议保持 4 核 4G

任务四:管理虚拟机生命周期

StratoVirt 与 QEMU 都通过 QMP 管理虚拟机。QEMU 的 QMP 在建立连接后需要先执行一次 qmp_capabilities 握手,这是与 StratoVirt 的最大差异。

步骤1 连接 QMP

新开一个 SSH 终端(虚拟机已在后台运行),执行:

ncat -U /tmp/qmp1.socket

会收到 QEMU 的问候消息:

{"QMP": {"version": {"qemu": {"micro": 0, "minor": 2, "major": 6}, "package": "qemu-6.2.0-88.oe2203"}, "capabilities": ["oob"]}}

步骤2 执行 QMP 握手

{"execute":"qmp_capabilities"}

返回:

{"return": {}}

没有这一步,后续命令会返回 CommandNotFound 或 QMP capability negotiation failed。StratoVirt 的旧示例中没有这一步,直接敲命令即可,二者不同。

步骤3 查询虚拟机信息

查询状态:

{"execute":"query-status"}

返回:

{"return": {"status": "running", "singlestep": false, "running": true}}

查询 vCPU:

{"execute":"query-cpus-fast"}

返回 4 个 vCPU 的信息(thread-id、qom-path、cpu-index 等)。

QEMU 6.2 已移除 query-cpus 命令,请使用 query-cpus-fast。

查询 vCPU 上线情况:

{"execute":"query-hotpluggable-cpus"}

返回 8 个可能的 vCPU,其中 core-id 0~3 带有 qom-path(在线),4~7 没有(离线)。这与原 StratoVirt 实验中"online 的 vCPU 有 qom-path"的结论一致。

步骤4 暂停虚拟机

{"execute":"stop"}

查询状态确认:

{"execute":"query-status"}

返回 "status": "paused"。

步骤5 恢复虚拟机

{"execute":"cont"}

再次查询状态,返回 "status": "running"。

步骤6 退出虚拟机

{"execute":"quit"}

QMP 连接会断开,虚拟机进程退出。按 Ctrl+C 退出 ncat,再按回车回到主机命令行。

提示:直接按 Ctrl+C 断开 ncat 不会关闭虚拟机;只有发送 quit 才会退出虚拟机进程。

重新启动虚拟机:

/opt/vm/start-vm.sh

步骤7 与 StratoVirt QMP 的差异对照

操作StratoVirtQEMU(本实验)
握手无必须先 {"execute":"qmp_capabilities"}
查询 CPUquery-cpusquery-cpus-fast
查询拓扑query-hotpluggable-cpus同名,可用
暂停/恢复/退出stop / cont / quit同名,可用
管理通道/tmp/qmp1.socket/tmp/qmp1.socket

任务五:管理虚拟机资源

本任务中的热插拔操作需要虚拟机启动时预留 PCIe 根端口(启动脚本中的 rp1、rp2),否则会报错 Bus 'pcie.0' does not support hotplugging。

步骤1 热插拔磁盘

准备数据盘

公有云 ECS 没有多余的空闲块设备,本实验用文件模拟一块 512 MiB 的磁盘:

dd if=/dev/zero of=/opt/vm/data1.img bs=1M count=512 status=none
mkfs.ext4 -q /opt/vm/data1.img

热插磁盘

在 QMP 终端中依次执行:

{"execute":"blockdev-add","arguments":{"node-name":"drive-0","driver":"file","filename":"/opt/vm/data1.img"}}
{"execute":"device_add","arguments":{"driver":"virtio-blk-pci","drive":"drive-0","id":"drive-0","bus":"rp1"}}

两条命令均返回 {"return": {}}。

在虚拟机内验证

通过串口控制台登录虚拟机,执行:

lsblk

可以看到新增的 vdb:

NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
vda    254:0    0  1.2G  0 disk /
vdb    254:16   0  512M  0 disk

挂载并写入数据:

mkdir -p /mnt/data
mount /dev/vdb /mnt/data
df -h /mnt/data
echo "hello stratovirt" > /mnt/data/test.txt
cat /mnt/data/test.txt

热拔磁盘

先在虚拟机内卸载文件系统(否则设备可能处于 busy 状态):

umount /mnt/data

在 QMP 终端中执行:

{"execute":"device_del","arguments":{"id":"drive-0"}}

等待数秒(等 guest 完成设备移除),再执行:

{"execute":"blockdev-del","arguments":{"node-name":"drive-0"}}

在虚拟机内再次执行 lsblk,vdb 已消失。

注意:device_del 后立即执行 blockdev-del 可能报 Node drive-0 is in use,等待几秒后重试即可;只要 guest 中 vdb 已消失,稍后一定能删除成功。

步骤2 热插拔网卡

在宿主机创建 tap 设备

ip tuntap add tap0 mode tap
ip link set tap0 up
ip addr add 10.0.0.1/24 dev tap0

热插网卡

在 QMP 终端中执行:

{"execute":"netdev_add","arguments":{"type":"tap","id":"net-0","ifname":"tap0","script":"no","downscript":"no"}}
{"execute":"device_add","arguments":{"driver":"virtio-net-pci","netdev":"net-0","id":"net-0","bus":"rp2"}}

在虚拟机内验证

ls /sys/class/net
ip link set ens2 up
ip addr add 10.0.0.2/24 dev ens2
ip -brief addr show ens2

新网卡名称可能是 ens2 或 eth1,以 ls /sys/class/net 的实际结果为准。

在宿主机验证连通性

ping -c 2 10.0.0.2

预期可以 ping 通(0% packet loss)。

热拔网卡

{"execute":"device_del","arguments":{"id":"net-0"}}
{"execute":"netdev_del","arguments":{"id":"net-0"}}

虚拟机内 ls /sys/class/net 中对应的网卡消失。

说明:本实验只为验证热插拔,tap 网卡与 ECS 主网卡 eth0 无关,不会影响 SSH 连接。

步骤3 Balloon 设备使用

Balloon 用于从虚拟机回收空闲内存。启动脚本中已经加入 -device virtio-balloon-pci,id=balloon0。

在虚拟机内查看内存

free -m

初始 total 约为 3.9 GiB(启动时配置 4 GiB)。

通过 QMP 回收内存

将虚拟机内存调整为 1 GiB(单位:字节):

{"execute":"balloon","arguments":{"value":1073741824}}

执行后会收到 BALLOON_CHANGE 事件。查询当前实际内存:

{"execute":"query-balloon"}

返回类似:

{"return": {"actual": 4160749568}}

再次在虚拟机内执行 free -m,可以看到 total 明显下降(逐步回收,约 1 GiB)。

恢复内存

{"execute":"balloon","arguments":{"value":4294967296}}

说明:Balloon 回收的是 guest 中空闲的内存,不是硬性限制;guest 内存紧张时会自动归还。


任务六:虚拟机内存快照

StratoVirt 支持对暂停状态的虚拟机制作快照,并支持以快照恢复。QEMU 同样支持,但快照文件格式不同:StratoVirt 生成 memory + state 两个目录,QEMU 生成单个迁移流文件。

步骤1 暂停虚拟机

在 QMP 终端中执行:

{"execute":"stop"}
{"execute":"query-status"}

状态应为 paused。

步骤2 制作快照

QEMU 6.2 不支持 file: 迁移协议,使用 exec: 协议把迁移流写入文件:

{"execute":"migrate","arguments":{"uri":"exec:cat > /opt/vm/snapshot.bin"}}

查询迁移状态:

{"execute":"query-migrate"}

当返回中包含 "status": "completed" 时,快照制作完成:

{"return": {"status": "completed", ...}}

在宿主机查看快照文件:

ls -lh /opt/vm/snapshot.bin

文件大小约为虚拟机实际使用的内存量(约 190 MB)。

步骤3 退出虚拟机

{"execute":"quit"}

步骤4 从快照恢复虚拟机

使用与启动时完全相同的设备配置,并增加 -incoming 参数(QMP 使用新的 socket 路径):

qemu-system-aarch64 \
  -machine virt,gic-version=3 \
  -accel tcg,thread=multi -cpu cortex-a72 \
  -smp 4,maxcpus=8 -m 4G \
  -kernel /opt/vm/std-vmlinux.bin \
  -append "root=/dev/vda console=ttyAMA0 rw reboot=k panic=1" \
  -drive file=/opt/vm/openEuler-22.03-LTS-stratovirt-aarch64.img,if=virtio,format=raw \
  -device virtio-balloon-pci,id=balloon0 \
  -device pcie-root-port,id=rp1,chassis=1,slot=1 \
  -device pcie-root-port,id=rp2,chassis=2,slot=2 \
  -display none \
  -qmp unix:/tmp/qmp2.socket,server=on,wait=off \
  -chardev socket,id=con0,path=/opt/vm/console.sock,server=on,wait=off,logfile=/opt/vm/console.log,logappend=on \
  -serial chardev:con0 \
  -incoming "exec:cat /opt/vm/snapshot.bin" \
  -pidfile /opt/vm/qemu.pid -daemonize

步骤5 确认恢复结果

连接新的 QMP:

ncat -U /tmp/qmp2.socket

执行握手和查询:

{"execute":"qmp_capabilities"}
{"execute":"query-migrate"}
{"execute":"query-status"}
  • query-migrate 返回 "status": "completed" 表示快照加载完成;
  • 此时 query-status 可能返回 paused,执行 {"execute":"cont"} 恢复运行;
  • 再次查询状态为 running。

通过串口控制台重新登录,确认虚拟机正常运行:

socat -,raw,echo=0 unix-connect:/opt/vm/console.sock

注意:恢复时 -incoming 的路径、内存大小、设备数量必须与快照时一致,否则会恢复失败。


任务七(选做):对接 iSula 安全容器

重要说明:Kata Containers 使用 StratoVirt 作为 hypervisor,启动安全容器同样需要 /dev/kvm,并且需要可访问的容器镜像仓库。华为云 ECS 默认不支持嵌套虚拟化,因此本任务无法在普通公有云 ECS 上完整运行。

本任务在 ECS 上可完成的部分:iSulad 安装、devicemapper 存储配置、isula info 验证、Kata 配置文件修改(作为演示)。安全容器的实际启动需要支持 KVM 的环境(裸金属服务器或支持嵌套虚拟化的规格)。

步骤1 安装 iSulad

openEuler 22.03 官方仓库已提供 iSulad,无需修改 yum 源(原手册切换到 21.09 源的做法在公有云上容易破坏软件源,不建议使用):

提示:修改配置前先备份 /etc/isulad/daemon.json(cp /etc/isulad/daemon.json /etc/isulad/daemon.json.bak);不同 iSulad 版本的字段可能略有差异,最终以 isula info 的输出为准。

yum install -y iSulad lvm2 --nogpgcheck
systemctl enable --now isulad
isula version

步骤2 配置 devicemapper 存储

使用文件模拟一块 10 GiB 块设备:

dd if=/dev/zero of=/opt/isula_images bs=1G count=10
losetup /dev/loop0 /opt/isula_images
pvcreate /dev/loop0
vgcreate isulaVG0 /dev/loop0
lvcreate --wipesignatures y -n thinpool isulaVG0 -l 95%VG
lvcreate --wipesignatures y -n thinpoolmeta isulaVG0 -l 1%VG
lvconvert -y --zero n -c 512K --thinpool isulaVG0/thinpool --poolmetadata isulaVG0/thinpoolmeta

创建自动扩容配置 /etc/lvm/profile/isulaVG0-thinpool.profile:

activation {
    thin_pool_autoextend_threshold=80
    thin_pool_autoextend_percent=20
}

应用配置:

lvchange --metadataprofile isulaVG0-thinpool isulaVG0/thinpool

步骤3 修改 iSulad 配置

编辑 /etc/isulad/daemon.json,将存储驱动改为 devicemapper:

"storage-driver": "devicemapper",
"storage-opts": [
  "dm.thinpooldev=/dev/mapper/isulaVG0-thinpool",
  "dm.fs=ext4",
  "dm.min_free_space=10%"
]

若只是验证 iSulad 基础功能(不使用 Kata),将默认运行时保持为 runc:

"default-runtime": "runc"

重启并验证:

systemctl daemon-reload
systemctl restart isulad
isula info

isula info 中应能看到 Storage Driver: devicemapper。

daemon.json 是一个完整的 JSON 文件,修改时保留原有字段并注意逗号。改完建议先校验语法,再重启服务:

python3 -m json.tool /etc/isulad/daemon.json > /dev/null && echo "JSON OK"

步骤4 配置 Kata Containers 使用 StratoVirt(需 KVM)

安装 Kata:

yum install -y kata-containers --nogpgcheck

编辑 /usr/share/defaults/kata-containers/configuration.toml,将 hypervisor 配置为 StratoVirt:

[hypervisor.stratovirt]
path = "/usr/bin/stratovirt"
kernel = "/var/lib/kata/vmlinux.bin"
initrd = "/var/lib/kata/kata-containers-initrd.img"
block_device_driver = "virtio-mmio"
use_vsock = true
internetworking_model = "tcfilter"
sandbox_cgroup_with_emulator = false
disable_new_netns = false
disable_block_device_use = false
disable_vhost_net = true

并将 iSulad 的默认运行时改为 Kata:

"default-runtime": "io.containerd.kata.v2"

重启 iSulad:

systemctl restart isulad

步骤5 运行安全容器(在支持 KVM 的环境执行)

isula run -tid --runtime "io.containerd.kata.v2" --net=none --name test busybox:latest sh
isula ps -a
isula exec -it test sh

在无 KVM 的 ECS 上,该命令通常会失败(容器退出码 125),isula logs test 或 journalctl 中一般能看到 StratoVirt/KVM 启动失败的信息,这是环境限制而非配置错误。

步骤6 在 ECS 上验证 iSulad 基础功能(替代练习)

如果只是练习 iSulad 命令与存储配置,可以在 ECS 上使用 runc 运行时:

isula run -tid --runtime runc --net=none --name test busybox:latest sh
isula ps -a
isula exec -it test sh

需要能够访问容器镜像仓库(如华为云 SWR 或实验提供的私有仓库)。若无法拉取镜像,可用 isula load -i <镜像tar包> 离线导入。


任务八:清理环境

实验完成后,按顺序清理,避免占用磁盘和端口。

步骤1 停止虚拟机

/opt/vm/stop-vm.sh

或手动:

kill "$(cat /opt/vm/qemu.pid)"

步骤2 删除临时文件

rm -f /tmp/qmp1.socket /tmp/qmp2.socket /tmp/sv.qmp /tmp/sv.log
rm -f /opt/vm/console.sock /opt/vm/snapshot.bin /opt/vm/data1.img
rm -f /opt/vm/console.log /opt/vm/console.log.old /opt/vm/console.log.prev /opt/vm/console.log.bak
ip link del tap0 2>/dev/null || true

步骤3 可选:删除镜像与软件

如需释放磁盘空间(镜像约 1.3 GiB):

rm -f /opt/vm/openEuler-22.03-LTS-stratovirt-aarch64.img
rm -f /opt/vm/openEuler-22.03-LTS-stratovirt-aarch64.img.xz
rm -f /opt/vm/std-vmlinux.bin

如需卸载可选组件:

systemctl stop isulad 2>/dev/null || true
yum remove -y iSulad kata-containers 2>/dev/null || true

步骤4 释放云资源

实验结束后,在华为云控制台删除 ECS 和弹性公网 IP,避免继续计费。


实验总结

通过本次实验:

  1. 理解了 StratoVirt 的架构与"只支持 KVM"的加速器限制;
  2. 掌握了 StratoVirt 的安装,以及用 /dev/kvm、dmesg 判断主机是否支持嵌套虚拟化;
  3. 掌握了在公有云 ECS 上使用 QEMU/TCG 运行 openEuler 官方 StratoVirt 镜像;
  4. 掌握了通过 QMP 查询状态、暂停/恢复/退出虚拟机;
  5. 掌握了磁盘、网卡热插拔与 Balloon 内存回收;
  6. 掌握了虚拟机内存快照的制作与恢复;
  7. 了解了 StratoVirt 对接 iSula/Kata 安全容器的配置方法与 KVM 依赖。

思考题

  1. 为什么 StratoVirt 在华为云 ECS 上无法启动?如何判断一台主机是否具备运行条件?
  2. vmlinux.bin 和 std-vmlinux.bin 有什么区别?选错会出现什么现象?
  3. QMP 中 query-hotpluggable-cpus 返回的 qom-path 代表什么?
  4. 热插拔磁盘时,为什么 device_add 要指定 bus=rp1?不指定会报什么错?
  5. QEMU 的内存快照与 StratoVirt 的快照文件结构有什么不同?恢复时为什么需要执行 cont?
  6. 如果实验环境换成裸金属服务器,如何改回使用 StratoVirt?需要修改哪些参数?

参考要点:

  1. 没有 /dev/kvm,dmesg 显示 HYP mode not available;StratoVirt 只支持 KVM,无 TCG 后端。
  2. microvm 内核只带 virtio-mmio 设备支持,没有 virtio-blk-pci;配标准镜像会 VFS: Cannot open root device "vda"。
  3. qom-path 表示该 vCPU 已经上线;offline 的 vCPU 没有该字段。
  4. pcie.0 根总线不支持直接热插拔,必须挂到 pcie-root-port 上,否则报 Bus 'pcie.0' does not support hotplugging。
  5. StratoVirt 生成 memory/state 目录,QEMU 生成单个迁移流文件;-incoming 加载完成后 QEMU 处于 paused,需要 cont 恢复运行。
  6. 使用 stratovirt -machine virt -accel kvm,把 -drive/-device 换成 StratoVirt 的 virtio-blk、virtio-net 参数(见附录 D)。

附录 A:华为云 ECS 采购与初始化清单

检查项要求检查命令
架构aarch64uname -m
操作系统openEuler 22.03 LTScat /etc/os-release
CPU/内存≥ 4 vCPU / 8 GiB(建议 8/16)nproc; free -h
系统盘≥ 80 GiBdf -h /
公网 IP已绑定ip addr
SSH安全组放通 22本地 ssh root@EIP
软件源华为云 openEuler repocat /etc/yum.repos.d/openEuler.repo
KVM无(预期)ls /dev/kvm

附录 B:常见问题(FAQ)

Q1:安装软件时提示 GPG 校验失败怎么办?

在命令后加 --nogpgcheck,例如:

yum install -y stratovirt --nogpgcheck

Q2:编译内核时提示缺少 flex、bison、dwarves 等工具?

yum install -y flex bison elfutils-libelf-devel dwarves bc openssl-devel \
               ncurses-devel rpm-build --nogpgcheck
yum groupinstall -y "Development Tools" --nogpgcheck

Q3:make -j vmlinux 执行很久,可以跳过吗?

可以。本实验直接使用官方 std-vmlinux.bin,编译内核仅为拓展了解。

Q4:虚拟机启动后内核 panic,提示找不到 vda?

使用了 microvm 内核 vmlinux.bin。改用 std-vmlinux.bin 即可。

Q5:虚拟机启动后串口没有任何输出?

  • 内核命令行必须是 console=ttyAMA0(不是 ttyS0);
  • 必须用 socat 接入 /opt/vm/console.sock;
  • 确认虚拟机进程存在:ps -p $(cat /opt/vm/qemu.pid)。

Q6:QMP 命令没有反应或报 CommandNotFound?

先执行一次握手:

{"execute":"qmp_capabilities"}

另外 QEMU 6.2 没有 query-cpus,请用 query-cpus-fast。

Q7:热插拔磁盘报 Bus 'pcie.0' does not support hotplugging?

启动时没有预留 PCIe 根端口。使用本手册的启动脚本(含 -device pcie-root-port),并在 device_add 中指定 bus=rp1。

Q8:migrate 使用 file:/path 报 expects a valid migration protocol?

QEMU 6.2 不支持 file: 迁移协议,改用:

{"execute":"migrate","arguments":{"uri":"exec:cat > /opt/vm/snapshot.bin"}}

Q9:快照恢复后虚拟机是 paused 状态?

正常现象,执行 {"execute":"cont"} 恢复运行。

Q10:ncat 或 socat 命令不存在?

yum install -y nmap socat --nogpgcheck

Q11:虚拟机运行很卡?

TCG 是纯软件模拟,性能有限。功能验证建议保持 -smp 4 -m 4G;若宿主机核数较少可降到 -smp 2 -m 2G。

Q12:磁盘空间不足?

官方镜像解压后约 1.2 GiB,压缩包约 131 MiB,快照约 190 MiB。实验完成后按任务八清理。

Q13:能否在 ECS 上直接使用 StratoVirt?

不能。StratoVirt 只支持 KVM,而 ECS 默认不暴露 /dev/kvm。需使用裸金属服务器或支持嵌套虚拟化的规格。

Q14:/dev/vhost-vsock 不存在怎么办?

modprobe vhost_vsock
ls -l /dev/vhost-vsock

该设备用于 Kata 安全容器,本实验的 QEMU 虚拟机不依赖它。

Q15:ECS 重启后虚拟机会自动启动吗?

不会。本实验的虚拟机是手工启动的进程,ECS 重启后需要重新执行 /opt/vm/start-vm.sh。


附录 C:命令速查表

功能命令
安装 StratoVirtyum install -y stratovirt --nogpgcheck
查看 StratoVirt 版本stratovirt -version
检查 KVMls -l /dev/kvm、dmesg | grep -i 'HYP mode'
安装运行环境yum install -y qemu-system-aarch64 nmap socat --nogpgcheck
启动虚拟机/opt/vm/start-vm.sh
连接串口socat -,raw,echo=0 unix-connect:/opt/vm/console.sock
连接 QMPncat -U /tmp/qmp1.socket
查看状态{"execute":"query-status"}
暂停/恢复/退出{"execute":"stop"} / {"execute":"cont"} / {"execute":"quit"}
查询 CPU{"execute":"query-cpus-fast"}
查询 CPU 拓扑{"execute":"query-hotpluggable-cpus"}
热插磁盘blockdev-add + device_add ... bus=rp1
热插网卡netdev_add + device_add ... bus=rp2
Balloon 回收内存{"execute":"balloon","arguments":{"value":1073741824}}
制作快照{"execute":"migrate","arguments":{"uri":"exec:cat > /opt/vm/snapshot.bin"}}
停止虚拟机/opt/vm/stop-vm.sh

附录 D:在支持 KVM 的环境使用 StratoVirt

如果实验环境是裸金属服务器或支持嵌套虚拟化的 ECS,可以直接使用 StratoVirt 完成同一套实验。

标准机(对应本手册的官方镜像):

stratovirt -machine virt -accel kvm \
  -kernel /opt/vm/std-vmlinux.bin \
  -append "root=/dev/vda console=ttyAMA0 rw" \
  -drive file=/opt/vm/openEuler-22.03-LTS-stratovirt-aarch64.img,id=rootfs \
  -m 4G -smp 4 -nographic

microvm(对应官方 microvm 内核 + virtio-mmio):

先下载 microvm 专用内核(本手册任务二默认只下载了标准机内核):

cd /opt/vm
wget https://dl-cdn.openeuler.openatom.cn/openEuler-22.03-LTS/stratovirt_img/aarch64/vmlinux.bin

再执行:

stratovirt -machine microvm -accel kvm \
  -kernel /opt/vm/vmlinux.bin \
  -append "root=/dev/vda console=ttyAMA0 rw reboot=k panic=1" \
  -drive file=/opt/vm/openEuler-22.03-LTS-stratovirt-aarch64.img,id=rootfs \
  -device virtio-blk-device,drive=rootfs,id=rootfs \
  -qmp unix:/tmp/qmp1.socket,server,nowait \
  -m 4G -smp 4 -serial stdio

注意:StratoVirt 的 QMP 不需要 qmp_capabilities 握手,query-cpus 等命令也与 QEMU 略有差异,具体以 StratoVirt 版本文档为准。

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐