强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

QEMU 虚拟化完全指南 / 14 - 虚拟机测试

14 - 虚拟机测试

掌握使用 QEMU 进行自动化测试、CI/CD 集成,以及 libguestfs/guestfs-tools 的高级运维。


14.1 QEMU 测试概述

QEMU 在测试领域有广泛的应用:

场景工具说明
操作系统测试QEMU + cloud-init快速部署测试 VM
内核测试QEMU + 内核编译测试自编译内核
文件系统测试libguestfs无需启动 VM 操作磁盘
网络测试QEMU + TAP/桥接虚拟网络拓扑
安全测试QEMU 沙箱恶意软件分析
CI/CDQEMU + Docker多架构测试

14.2 自动化虚拟机测试

创建测试用虚拟机脚本

#!/bin/bash
# test-vm.sh - 自动化 VM 测试脚本

set -euo pipefail

VM_NAME="test-vm-$$"
DISK="test-disk-$$.qcow2"
CLOUD_IMG="ubuntu-22.04-cloudimg-amd64.img"
SSH_PORT=$((20000 + RANDOM % 40000))
TIMEOUT=300

cleanup() {
    echo "清理资源..."
    [ -f "${DISK}" ] && rm -f "${DISK}"
    [ -f "seed-$$.iso" ] && rm -f "seed-$$.iso"
    [ -f "meta-data.$$" ] && rm -f "meta-data.$$"
    [ -f "user-data.$$" ] && rm -f "user-data.$$"
    pkill -f "qemu.*${VM_NAME}" 2>/dev/null || true
}
trap cleanup EXIT

# 准备磁盘
qemu-img create -f qcow2 -b "${CLOUD_IMG}" -F qcow2 "${DISK}" 40G

# 准备 cloud-init
cat > "meta-data.$$" << EOF
instance-id: ${VM_NAME}
local-hostname: ${VM_NAME}
EOF

cat > "user-data.$$" << 'EOF'
#cloud-config
users:
  - name: test
    ssh_authorized_keys:
      - ssh-rsa AAAA...  # 替换为你的公钥
    sudo: ['ALL=(ALL) NOPASSWD:ALL']
password: test
chpasswd:
  expire: false
ssh_pwauth: true
EOF

cloud-localds "seed-$$.iso" "user-data.$$" "meta-data.$$"

# 启动虚拟机
qemu-system-x86_64 \
  -name "${VM_NAME}" \
  -enable-kvm \
  -cpu host \
  -m 2G \
  -smp 2 \
  -drive file="${DISK}",format=qcow2,if=virtio \
  -drive file="seed-$$.iso",format=raw,if=virtio \
  -netdev user,id=net0,hostfwd=tcp::${SSH_PORT}-:22 \
  -device virtio-net-pci,netdev=net0 \
  -display none \
  -daemonize

# 等待 VM 启动
echo "等待 VM 启动 (端口 ${SSH_PORT})..."
for i in $(seq 1 ${TIMEOUT}); do
    if ssh -o StrictHostKeyChecking=no -o ConnectTimeout=2 \
      -p ${SSH_PORT} test@localhost "echo OK" 2>/dev/null; then
        echo "VM 启动成功 (${i}秒)"
        break
    fi
    sleep 1
done

# 执行测试
echo "执行测试..."
ssh -o StrictHostKeyChecking=no -p ${SSH_PORT} test@localhost << 'TEST'
    echo "=== 系统信息 ==="
    uname -a
    cat /etc/os-release | head -5

    echo "=== 磁盘使用 ==="
    df -h

    echo "=== 内存使用 ==="
    free -h

    echo "=== 运行测试命令 ==="
    echo "安装测试包..."
    sudo apt-get update -qq
    sudo apt-get install -y -qq curl

    echo "网络连通性测试..."
    curl -s --max-time 10 http://example.com > /dev/null && echo "网络: OK" || echo "网络: FAIL"

    echo "所有测试通过!"
TEST

echo "测试完成"

14.3 CI/CD 集成

GitHub Actions 集成

# .github/workflows/test.yml
name: VM Tests

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test-vm:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y qemu-system-x86 qemu-utils cloud-image-utils
      
      - name: Download cloud image
        run: |
          wget -q https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
          qemu-img resize jammy-server-cloudimg-amd64.img 20G
      
      - name: Prepare cloud-init
        run: |
          cat > user-data << 'EOF'
          #cloud-config
          users:
            - name: test
              sudo: ALL=(ALL) NOPASSWD:ALL
              ssh_authorized_keys:
                - ${{ secrets.SSH_PUBLIC_KEY }}
          EOF
          cat > meta-data << 'EOF'
          instance-id: ci-test
          local-hostname: ci-test
          EOF
          cloud-localds seed.iso user-data meta-data
      
      - name: Run VM test
        run: |
          # 启动 VM
          qemu-system-x86_64 \
            -enable-kvm -cpu host -m 2G -smp 2 \
            -drive file=jammy-server-cloudimg-amd64.img,format=qcow2,if=virtio \
            -drive file=seed.iso,format=raw,if=virtio \
            -netdev user,id=net0,hostfwd=tcp::2222-:22 \
            -device virtio-net-pci,netdev=net0 \
            -display none -daemonize
          
          # 等待启动
          for i in $(seq 1 120); do
            ssh -o StrictHostKeyChecking=no -o ConnectTimeout=2 \
              -p 2222 test@localhost "echo OK" 2>/dev/null && break
            sleep 1
          done
          
          # 执行测试
          ssh -o StrictHostKeyChecking=no -p 2222 test@localhost \
            "sudo apt-get update && sudo apt-get install -y curl && curl -s http://example.com"

GitLab CI 集成

# .gitlab-ci.yml
vm-test:
  stage: test
  tags:
    - kvm
  before_script:
    - apt-get update && apt-get install -y qemu-system-x86 qemu-utils cloud-image-utils
  script:
    - wget -q https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img
    - qemu-img resize jammy-server-cloudimg-amd64.img 20G
    - cloud-localds seed.iso user-data meta-data
    - qemu-system-x86_64 -enable-kvm -cpu host -m 2G -smp 2 -drive file=jammy-server-cloudimg-amd64.img,format=qcow2,if=virtio -drive file=seed.iso,format=raw,if=virtio -netdev user,id=net0,hostfwd=tcp::2222-:22 -device virtio-net-pci,netdev=net0 -display none -daemonize
    - sleep 60
    - ssh -o StrictHostKeyChecking=no -p 2222 test@localhost "echo 'VM test passed'"

14.4 libguestfs 简介

libguestfs 是一个用于访问和修改虚拟机磁盘镜像的工具库,无需启动虚拟机。

安装 libguestfs

# Debian/Ubuntu
sudo apt install -y libguestfs-tools guestfs-tools

# Fedora/RHEL
sudo dnf install -y libguestfs-tools guestfs-tools

# Arch Linux
sudo pacman -S libguestfs

guestfish 交互工具

# 启动 guestfish 交互式 Shell
guestfish --ro -a disk.qcow2

# 在 guestfish 中操作
><fs> run
><fs> list-filesystems
><fs> mount /dev/sda1 /
><fs> cat /etc/hostname
><fs> ls /
><fs> download /etc/passwd /tmp/passwd
><fs> upload /tmp/test.txt /tmp/test.txt
><fs> exit

guestfish 单命令模式

# 读取文件
guestfish --ro -a disk.qcow2 -i cat /etc/hostname

# 列出文件
guestfish --ro -a disk.qcow2 -i ls /etc/

# 下载文件
guestfish --ro -a disk.qcow2 -i download /var/log/syslog /tmp/syslog

# 上传文件
guestfish --rw -a disk.qcow2 -i upload /tmp/config.conf /etc/app/config.conf

# 修改文件
guestfish --rw -a disk.qcow2 -i write /etc/hostname "new-hostname"

14.5 guestfs-tools 命令行工具

virt-cat - 读取虚拟机文件

# 读取虚拟机中的文件
virt-cat -a disk.qcow2 /etc/hostname

# 读取日志
virt-cat -a disk.qcow2 /var/log/syslog | tail -100

# 读取二进制文件
virt-cat -a disk.qcow2 /etc/shadow

virt-edit - 编辑虚拟机文件

# 编辑虚拟机中的文件
virt-edit -a disk.qcow2 /etc/hostname

# 使用 sed 替换
virt-edit -a disk.qcow2 /etc/ssh/sshd_config \
  -e 's/^#PermitRootLogin.*/PermitRootLogin no/'

virt-df - 查看虚拟机磁盘使用

# 查看虚拟机磁盘使用情况
virt-df -a disk.qcow2

# 人类可读格式
virt-df -h -a disk.qcow2

# 输出示例:
# Filesystem                        Size       Used  Available  Use%
# disk.qcow2:/dev/sda1              39.0G      3.2G      33.8G   9%

virt-filesystems - 查看文件系统

# 列出虚拟机中的文件系统
virt-filesystems -a disk.qcow2

# 显示详细信息
virt-filesystems -a disk.qcow2 --all --long

# 显示分区
virt-filesystems -a disk.qcow2 --partitions

virt-inspector - 检查操作系统

# 检测虚拟机的操作系统
virt-inspector -a disk.qcow2

# 输出 XML 格式
virt-inspector -a disk.qcow2 --xml

virt-customize - 自定义虚拟机镜像

# 安装软件包
virt-customize -a disk.qcow2 --install vim,curl,wget

# 设置主机名
virt-customize -a disk.qcow2 --hostname my-server

# 设置密码
virt-customize -a disk.qcow2 --root-password password:mysecret

# 添加 SSH 密钥
virt-customize -a disk.qcow2 --ssh-inject root:file:/path/to/id_rsa.pub

# 运行自定义脚本
virt-customize -a disk.qcow2 --run-command 'apt-get update && apt-get upgrade -y'

# 设置时区
virt-customize -a disk.qcow2 --timezone Asia/Shanghai

# 启用服务
virt-customize -a disk.qcow2 --firstboot-command 'systemctl enable nginx'

virt-sysprep - 清理虚拟机

# 清理虚拟机敏感信息(用于模板/克隆)
virt-sysprep -a disk.qcow2

# 查看支持的操作
virt-sysprep --list

# 选择性清理
virt-sysprep -a disk.qcow2 \
  --operations bash-history,logfiles,tmp-files,hostname,ssh-hostkeys,machine-id

14.6 virt-builder 快速构建

# 列出可用的预构建镜像
virt-builder --list

# 构建 Ubuntu 22.04 镜像
virt-builder ubuntu-22.04 \
  --output ubuntu-22.04-custom.qcow2 \
  --format qcow2 \
  --size 40G \
  --hostname my-server \
  --root-password password:secret \
  --install vim,curl \
  --timezone Asia/Shanghai \
  --run-command 'apt-get update'

# 使用自定义脚本
virt-builder ubuntu-22.04 \
  --output ubuntu-custom.qcow2 \
  --format qcow2 \
  --firstboot firstboot.sh

14.7 virt-v2v 虚拟机转换

# 将 VMware 虚拟机转换为 KVM
virt-v2v -i vmx VMware.vmx -o local -os /var/lib/libvirt/images/

# 将 VirtualBox 虚拟机转换
virt-v2v -i libvirt vbox-vm -o local -os /var/lib/libvirt/images/

# 通过 OVA 文件转换
virt-v2v -i ova vm-export.ova -o local -os /var/lib/libvirt/images/

14.8 测试框架集成

Avocado 测试框架

# 安装 Avocado
pip install avocado-framework

# 创建 QEMU 测试用例
cat > qemu_test.py << 'EOF'
from avocado import Test

class QEMUTest(Test):
    def test_vm_boot(self):
        """测试虚拟机启动"""
        import subprocess
        result = subprocess.run(
            ['qemu-system-x86_64', '-enable-kvm', '-cpu', 'host',
             '-m', '1G', '-drive', 'file=test.qcow2,format=qcow2',
             '-display', 'none', '-serial', 'null', '-monitor', 'none',
             '-no-reboot'],
            capture_output=True, timeout=60
        )
        self.assertEqual(result.returncode, 0)

    def test_disk_create(self):
        """测试磁盘创建"""
        import subprocess
        result = subprocess.run(
            ['qemu-img', 'create', '-f', 'qcow2', 'test.qcow2', '10G'],
            capture_output=True
        )
        self.assertEqual(result.returncode, 0)
EOF

# 运行测试
avocado run qemu_test.py

pytest 集成

# test_qemu.py
import pytest
import subprocess
import os

@pytest.fixture
def test_disk():
    """创建测试磁盘"""
    subprocess.run(['qemu-img', 'create', '-f', 'qcow2', '/tmp/test.qcow2', '10G'], check=True)
    yield '/tmp/test.qcow2'
    os.unlink('/tmp/test.qcow2')

def test_qemu_version():
    result = subprocess.run(['qemu-system-x86_64', '--version'], capture_output=True, text=True)
    assert result.returncode == 0
    assert 'QEMU' in result.stdout

def test_disk_info(test_disk):
    result = subprocess.run(['qemu-img', 'info', test_disk], capture_output=True, text=True)
    assert result.returncode == 0
    assert 'qcow2' in result.stdout

要点回顾

要点核心内容
自动化测试cloud-init + SSH 实现无人值守测试
CI/CDGitHub Actions / GitLab CI 集成 QEMU
libguestfs无需启动 VM 即可操作磁盘文件
guestfs-toolsvirt-cat/edit/df/inspect/customize/sysprep
virt-builder快速构建预配置的 VM 镜像

注意事项

KVM 支持: CI/CD 环境中运行 QEMU 需要 KVM 支持。GitHub Actions 的 ubuntu-latest 支持 KVM,但需要确保 /dev/kvm 权限正确。

测试隔离: 每个测试应该创建独立的虚拟机和磁盘,避免测试间干扰。

资源限制: CI/CD 环境资源有限,虚拟机配置不宜过大(建议 1-2G 内存,1-2 vCPU)。


扩展阅读


下一步

15 - Docker 中的 QEMU:学习在 Docker 中使用 QEMU 进行多架构构建。