最佳实践

概述

参考:

注意:本最佳实践仅适用于独立使用 qemu-img、qemu-system 等 KVM/QEMU 的命令行工具,不包括 libvirtd 的工具

QEMU 命令行的一般形式可以表示为:

$ qemu-system-x86_64 [machine opts] \ [cpu opts] \ [accelerator opts] \ [device opts] \ [backend opts] \ [interface opts] \ [boot opts]

在下面的示例中,我们首先定义一台机器,它是用于运行 Aarch64 来宾的通用平台。我们启用虚拟化,因此我们可以在模拟来宾中使用 KVM。由于机器带有一些内置的 pflash 设备,我们给它们命名,以便我们稍后可以覆盖默认值。virtvirt

$ qemu-system-aarch64 \ -machine type=virt,virtualization=on,pflash0=rom,pflash1=efivars \ -m 4096 \

然后,我们使用为我们提供 QEMU 能够模拟的所有 Arm 功能的选项定义 4 个 vCPU。我们启用了更加仿真友好的 Arm 指针身份验证算法实现。我们明确指定 TCG 加速,即使 QEMU 无论如何都会默认为它。

-cpu max,pauth-impdef=on \
-smp 4 \
-accel tcg \

由于平台没有任何默认网络或存储设备,我们需要定义它们。我们给他们 id 以便我们稍后可以将他们与后端链接。

-device virtio-net-pci,netdev=unet \ -device virtio-scsi-pci \ -device scsi-hd,drive=hd \

我们将用户模式网络连接到我们的网络设备。由于无法从外部直接访问用户模式网络,我们将本地主机端口 2222 转发到访客上的 ssh 端口。

-netdev user,id=unet,hostfwd=tcp::2222-:22 \

我们将来宾可见块设备连接到为来宾预留的 LVM 分区。

-blockdev driver=raw,node-name=hd,file.driver=host_device,file.filename=/dev/lvm-disk/debian-bullseye-arm64 \

然后我们告诉 QEMU 将 QEMU Monitor 与串行端口输出进行多路复用(我们可以使用字符后端多路复用器中的键在两者之间切换)。由于没有默认的图形设备,我们禁用了显示,因为我们可以完全在终端中工作。

-serial mon:stdio \ -display none \

最后,我们覆盖默认固件以确保我们有一些存储空间供 EFI 保留其配置。该固件负责查找磁盘、引导 grub 并最终运行我们的系统。

-blockdev node-name=rom,driver=file,filename=(pwd)/pc-bios/edk2-aarch64-code.fd,read-only=true \ -blockdev node-name=efivars,driver=file,filename=$HOME/images/qemu-arm64-efivars

全部(有问题)

qemu-system--x86_64 \ -machine type=virt,virtualization=on,pflash0=rom,pflash1=efivars \ -m 4096 \ -cpu max,pauth-impdef=on \ -smp 4 \ -accel tcg \ -device virtio-net-pci,netdev=unet \ -device virtio-scsi-pci \ -device scsi-hd,drive=hd \ -netdev user,id=unet,hostfwd=tcp::2222-:22 \ -blockdev driver=raw,node-name=hd,file.driver=host_device,file.filename=/dev/lvm-disk/debian-bullseye-arm64 \ -serial mon:stdio \ -display none \ -blockdev node-name=rom,driver=file,filename=(pwd)/pc-bios/edk2-aarch64-code.fd,read-only=true \ -blockdev node-name=efivars,driver=file,filename=$HOME/images/qemu-arm64-efivars

TODO:

qemu-system-x86_64 qemu-install-test.qcow2 \ -m 4096 \ -cdrom ./CentOS-7-x86_64-DVD-2009.iso \ -smp 2 \ -accel tcg \ -device virtio-net-pci,netdev=unet \ -device virtio-scsi-pci \ -netdev user,id=unet,hostfwd=tcp::2222-:22 \ -serial mon:stdio \ -vnc 0.0.0.0:10

应用示例

准备连接虚拟机的工具

  • 使用 vnc 客户端工具(vnc-viewer 等…) 连接并安装系统即可。
  • 我们也可以通过各种终端(XShell 等)的 X11 转发连接。在宿主机系统中安装 tigervnc 后,在系统下执行如下命令即可。
vncview :3

前期准备

创建 bridge 网络设备,并配置 ip,然后将宿主机的外部网卡关联的网络设备加入到 bridge 上。

export IPADDR="172.19.42.249/24" ip link add br0 type bridge ip addr add ${IPADDR} dev br0 ip link set dev eth0 master br0

创建一个 qcow2 格式的镜像文件,用作块设备

export VM_QCOW2_FILE="/var/lib/libvirt/images/test/qemu-install-test.qcow2" qemu-img create -f qcow2 ${VM_QCOW2_FILE} 10G

准备一个用于安装系统的 iso

export OS_ISO_PATH="/root/iso/CentOS-7-x86_64-DVD-2009.iso"

启动虚拟机并安装系统

使用 qemu-install-test.qcow2 文件启动虚拟机,并挂载系统镜像。

注意

  • 如果不分配内存,会提示无法加载 VFS 导致无法启动微型系统来安装系统。默认模拟 1 个 CPU。
  • :3 为 vncview 的访问时的端口,3 默认为 5903
qemu-system-x86_64 ${VM_QCOW2_FILE} \ -m 4096 \ -smp 1 \ -vnc 0.0.0.0:3 \ -cdrom ${OS_ISO_PATH}

连接虚拟机

完成安装

安装完成后,不用指定 cdrom 即可启动虚拟机

qemu-system-x86_64 ${VM_QCOW2_FILE} -m 4096 -vnc 0.0.0.0:3

启动一个正常可用的虚拟机

生成脚本

生成 -netdev 选项所用的启动脚本

cat > /etc/qemu-ifup <<\EOF #!/bin/bash BRIDGE=br0 if [ -n $1 ]; then ip link set dev $1 master ${BRIDGE} ip link set dev $1 up [ $? -eq 0 ] && exit 0 || exit 1 else echo "Error: no interface specified." exit 1 fi EOF chmod 755 /etc/qemu-ifup

启动虚拟机

qemu-system-x86_64 -m 4096 -smp 2 -name test \ -drive file=${VM_QCOW2_FILE},format=qcow2,if=virtio \ -netdev tap,id=n1 \ -device virtio-net,netdev=n1 \ -vnc :3

连接虚拟机

结语

现在是使用 qemu-system-x86_64 工具自动创建的 tap 设备,若是使用已经已经存在的网络设备,那么还需要创建一个 downscript 脚本,以便可以在虚拟机关闭时,自动处理,将网络设备从 bridge 上拆下来,否则下次再次启动,网络设备已经在 bridge 上,就会报错,导致虚拟机无法启动。

通过 virsh domxml-to-native 命令,转换出 wiki 来的 qemu-system 命令行其中一部分

其中使用 ... 省略了很多无用参数

# 使用 qemu-system 程序创建一个名为 desistdaydream.bj-net 的虚拟机 qemu-system-x86_64 -name desistdaydream.bj-net # 虚拟机使用哪种类型的机器,这里是 i440fx 红帽7 -machine pc-i440fx-rhel7.0.0,accel=kvm,usb=off,dump-guest-core=off # 虚拟机所使用的 CPU 类型 -cpu Skylake-Server-IBRS,-ds,-acpi,+ss,-ht,-tm,-pbe,-dtes64,-monitor,-ds_cpl,-vmx,-smx,-est,-tm2,-xtpr,-pdcm,-dca,-osxsave,-tsc_adjust,+clflushopt,-intel-pt,+pku,-ospke,+avx512vnni,+md-clear,+stibp,+ssbd,+hypervisor,-arat # 虚拟机的内存大小 -m 4096 -realtime mlock=off # 虚拟机有2个CPU,模拟成2个插槽,每个插槽的CPU有一个核心,每个核心1个线程 -smp 2,sockets=2,cores=1,threads=1 ...... # 虚拟机中 virtio-blk-pci 设备,是 VM 的硬盘 # 宿主机中 qcow2 文件,id 为 drive-virtio-disk0 # 两者通过 drive 中的 id参数 与 device 中的 drive 参数保持一致,进行关联 -drive file=/var/lib/libvirt/images/master-3.bj-net.qcow2,format=qcow2,...,id=drive-virtio-disk0,... -device virtio-blk-pci,...,drive=drive-virtio-disk0,... # 略 drive 中的 id 与 device 中的 drive 相同。 -drive if=none,id=drive-ide0-0-0,... -device ide-cd,bus=ide.0,...,drive=drive-ide0-0-0,... # 虚拟机中 virtio-net-pci 设备,是 VM 中的网卡 # 宿主机中 tap 设备,id 为hostnet0 # 两者通过 netdev 中的 id参数 与 device 中的 netdev 参数保持一致,进行关联。 -netdev tap,...id=hostnet0,... -device virtio-net-pci,...,netdev=hostnet0,... # 略,chardev 中的 id 与 device 中的 chardev 相同 -chardev pty,id=charserial0 -device isa-serial,chardev=charserial0,... # 略,chardev 中的 id 与 device 中的 chardev 相同 -chardev socket,id=charchannel0,path=/var/lib/libvirt/qemu/channel/target/domain--1-desistdaydream.bj-net/org.qemu.guest_agent.0,server,nowait -device virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=org.qemu.guest_agent.0 .....

最后修改 May 15, 2024: git, gitlab (c414ecd2)