用 QEMU 把虚拟机跑起来
目标
用提供的磁盘镜像真正启动一台 QEMU VM,并通过串口日志、monitor 套接字、hostfwd 监听套接字三种方式证明它还活着。
为什么重要
实际工作中会使用 libvirt 或云控制台,但出了问题,最终还是要读它底下的 QEMU 命令行。-netdev(主机一侧的后端)和 -device(客户机看到的网卡)为什么要分开、为什么必须明确指定 format=、hostfwd 监听套接字为什么与客户机启动无关而能立即打开——这些只有亲手写一遍命令行才能真正掌握。
本实验在虚拟机内运行,并在其中再启动一台虚拟机。 嵌套虚拟化已开启,所以有 /dev/kvm,QEMU 可以直接使用硬件加速。\n\n以前是在 Pod 中运行,没有 /dev/kvm,QEMU 只能靠逐条翻译指令的 TCG 软件仿真运行。客户机要花几分钟才能到达登录提示符,所以实验只能检查到“固件是否启动”为止。\n\n请从现有的加速器中选择使用。 -accel kvm 和 -accel tcg 相差几十倍。实际工作中的顺序也是一样——先看有没有 /dev/kvm,有就用它。评分器也会查看这台机器里有什么,并据此进行判定。
步骤
- 创建
/root/vmboot目录,并把/opt/vm/下提供的磁盘镜像的qemu-img info输出保存到/root/vmboot/base-info.txt。 - 创建以该镜像为后备文件的覆盖层
/root/vmboot/vm.qcow2。原始镜像不能改变。 - 编写
/root/vmboot/run.sh。必须全部包含以下要素。qemu-system-x86_64-accel tcg-m 512-smp 1-drive file=/root/vmboot/vm.qcow2,if=virtio,format=qcow2-netdev user,id=n0,hostfwd=tcp::12222-:22-device virtio-net-pci,netdev=n0-nographic-serial file:/root/vmboot/console.log-monitor unix:/root/vmboot/mon.sock,server,nowait
- 把可用加速器列表和
/dev/kvm是否存在,按以下两行写入/root/vmboot/accel.txt。ACCELS=<쉼표로 구분한 가속기 목록>/DEVKVM=<yes|no>(占位符为以逗号分隔的加速器列表) - 在后台运行
run.sh,等待 20 秒以上,然后确认/root/vmboot/console.log中留下了固件消息。日志中必须有SeaBIOS或Booting字符串。 - 向 monitor 套接字发送
info status,把响应保存到/root/vmboot/monitor.txt。响应中必须能看到running或paused。 - 确认
12222端口处于监听状态,并保存到/root/vmboot/hostfwd.txt。进程必须显示为qemu。 - 把
/root/vmboot/report.txt写成以下 5 行。ACCEL=tcg/MEM=512/VCPU=1/FWD_PORT=12222/DISK_IF=virtio
参考
- 用
qemu-system-x86_64 -accel help查看加速器列表。 - 后台运行采用
nohup bash /root/vmboot/run.sh >/root/vmboot/qemu.out 2>&1 &的形式。 - monitor 查询是
printf 'info status\n' | nc -U /root/vmboot/mon.sock。如果没有响应,用-q 1给一个退出等待时间。 - 常见错误 1:在
run.sh里把 QEMU 放到后台,评分时参数解析会变得困难。脚本要写成前台运行,后台处理留到执行时再做。 - 常见错误 2:不用覆盖层而直接使用原始镜像,再次做实验时状态会被污染。
确认提供的镜像
创建 /root/vmboot 目录,并把 /opt/vm/ 下提供的磁盘镜像的 qemu-img info 输出保存到 /root/vmboot/base-info.txt。
/opt/vm 下有准备好的镜像。请先确认格式和虚拟大小。
用覆盖层保护原始镜像
创建以该镜像为后备文件的覆盖层 /root/vmboot/vm.qcow2。原始镜像不能改变。
创建以原始镜像为后备文件的覆盖层,原始镜像就不会改变。别忘了明确指定后备文件的格式。
编写运行脚本
编写 /root/vmboot/run.sh。必须全部包含以下要素。
qemu-system-x86_64-accel tcg-m 512-smp 1-drive file=/root/vmboot/vm.qcow2,if=virtio,format=qcow2-netdev user,id=n0,hostfwd=tcp::12222-:22-device virtio-net-pci,netdev=n0-nographic-serial file:/root/vmboot/console.log-monitor unix:/root/vmboot/mon.sock,server,nowait
需要的标志是固定的。缺少任何一个,评分时都会被判错。后台运行要在脚本之外进行。
确认加速器
把可用加速器列表和 /dev/kvm 是否存在,按以下两行写入 /root/vmboot/accel.txt。
ACCELS=<쉼표로 구분한 가속기 목록> / DEVKVM=<yes|no>(占位符为以逗号分隔的加速器列表)
qemu-system-x86_64 有列出可用加速器的帮助。也请同时记录 /dev/kvm 是否存在。
真正启动并留下控制台日志
在后台运行 run.sh,等待 20 秒以上,然后确认 /root/vmboot/console.log 中留下了固件消息。日志中必须有 SeaBIOS 或 Booting 字符串。
有把串口输出发送到文件的选项。固件消息在启动后立即输出,所以不需要等很久。
向 monitor 套接字查询
向 monitor 套接字发送 info status,并把响应保存到 /root/vmboot/monitor.txt。响应中必须能看到 running 或 paused。
把 monitor 以 Unix 套接字方式打开,用 nc 的 -U 连接。把命令通过标准输入送进去即可。
确认端口转发
确认 12222 端口处于监听状态,并保存到 /root/vmboot/hostfwd.txt。进程必须显示为 qemu。
hostfwd 的监听套接字在 QEMU 启动后立即打开,与客户机是否启动无关。
VM 运行报告
把 /root/vmboot/report.txt 写成以下 5 行。
ACCEL=tcg / MEM=512 / VCPU=1 / FWD_PORT=12222 / DISK_IF=virtio
汇总前面步骤中确认的值。加速器和转发端口必须是真实的值。