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

QEMU 虚拟化完全指南 / 04 - 磁盘管理

04 - 磁盘管理

深入掌握 QEMU 磁盘镜像格式、快照管理、备份恢复、压缩优化与在线扩容的完整流程。


4.1 磁盘镜像格式详解

qcow2 格式

qcow2(QEMU Copy-On-Write version 2)是 QEMU 的原生磁镜像格式,也是最常用的格式:

特性说明
稀疏分配按需分配磁盘空间,初始占用极小
快照支持支持内部快照和外部快照
压缩支持 zlib/zstd 压缩
加密支持 AES/LUKS 加密
后备文件支持 backing file(增量镜像)
最大大小理论上 2 EB(exabytes)
# 创建 qcow2 镜像
qemu-img create -f qcow2 vm-disk.qcow2 40G

# 创建带预分配的 qcow2(推荐用于生产)
qemu-img create -f qcow2 -o preallocation=metadata vm-disk.qcow2 40G

# 创建带压缩的 qcow2
qemu-img create -f qcow2 -o compression_type=zstd vm-disk.qcow2 40G

# 查看详细信息
qemu-img info --output=json vm-disk.qcow2

qcow2 预分配模式

模式说明创建速度磁盘占用读性能写性能
off (默认)不预分配最快最小
metadata仅预分配元数据
falloc预分配空间(fallocate)中等最好最好
full完全预分配(填零)最大最好最好
# 对比预分配效果
qemu-img create -f qcow2 -o preallocation=off test-off.qcow2 10G
qemu-img create -f qcow2 -o preallocation=metadata test-meta.qcow2 10G
qemu-img create -f qcow2 -o preallocation=falloc test-falloc.qcow2 10G

# 查看实际磁盘占用
ls -lh test-*.qcow2
du -h test-*.qcow2

raw 格式

raw 格式是最简单的磁盘格式,直接映射扇区:

# 创建 raw 镜像
qemu-img create -f raw vm-disk.raw 40G

# 查看信息
qemu-img info vm-disk.raw
特性rawqcow2
性能最好接近(virtio + cache=writeback)
稀疏分配依赖宿主文件系统原生支持
快照❌ 不支持✅ 支持
压缩❌ 不支持✅ 支持
加密❌ 不支持✅ 支持
增量备份❌ 不支持✅ backing file
跨平台最好QEMU 专用
转换直接 dd需要 qemu-img convert

其他格式

QEMU 也支持读取和转换其他虚拟化平台的磁盘格式:

格式来源
vmdkVMware
vdiVirtualBox
vhdxHyper-V
vhdHyper-V (旧)
qedQEMU (旧)
parallelsParallels

4.2 qemu-img 管理工具

查看镜像信息

# 基本信息
qemu-img info disk.qcow2

# JSON 格式输出(便于脚本解析)
qemu-img info --output=json disk.qcow2

# 查看镜像的 backing chain
qemu-img info --backing-chain disk.qcow2

示例输出:

{
    "filename": "disk.qcow2",
    "format": "qcow2",
    "virtual-size": 42949672960,
    "cluster-size": 65536,
    "format-specific": {
        "type": "qcow2",
        "data": {
            "compat": "1.1",
            "compression-type": "zlib",
            "lazy-refcounts": false,
            "refcount-bits": 16
        }
    },
    "dirty-flag": false
}

格式转换

# qcow2 → raw
qemu-img convert -f qcow2 -O raw disk.qcow2 disk.raw

# raw → qcow2
qemu-img convert -f raw -O qcow2 disk.raw disk.qcow2

# VMDK → qcow2(从 VMware 迁移)
qemu-img convert -f vmdk -O qcow2 vmware-disk.vmdk qemu-disk.qcow2

# VDI → qcow2(从 VirtualBox 迁移)
qemu-img convert -f vdi -O qcow2 vbox-disk.vdi qemu-disk.qcow2

# 并行转换(提高速度)
qemu-img convert -f qcow2 -O qcow2 -T 4 disk.qcow2 new-disk.qcow2
# -T 指定并行 I/O 线程数

镜像检查与修复

# 检查镜像一致性
qemu-img check disk.qcow2

# 检查并修复(仅限 qcow2)
qemu-img check -r all disk.qcow2

# JSON 输出检查结果
qemu-img check --output=json disk.qcow2

4.3 增量镜像与后备文件

使用 backing file 创建增量镜像

增量镜像可以基于一个基础镜像创建多个差异镜像,节省磁盘空间:

# 创建基础镜像
qemu-img create -f qcow2 base.qcow2 40G
# ... 安装操作系统 ...

# 基于基础镜像创建增量镜像
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 snapshot1.qcow2
qemu-img create -f qcow2 -b base.qcow2 -F qcow2 snapshot2.qcow2

# 查看 backing chain
qemu-img info --backing-chain snapshot1.qcow2
增量镜像架构:
  base.qcow2 (只读,基础系统)
    ├── snapshot1.qcow2 (差异 1,用户数据)
    ├── snapshot2.qcow2 (差异 2,测试环境)
    └── snapshot3.qcow2 (差异 3,开发环境)

合并增量镜像

# 将增量镜像的差异合并回基础镜像(会修改基础镜像!)
qemu-img commit snapshot1.qcow2

# 或者将增量镜像"扁平化"为独立镜像
qemu-img convert -f qcow2 -O qcow2 snapshot1.qcow2 flat.qcow2

修改 backing file

# 重新设置 backing file
qemu-img rebase -b new-base.qcow2 -F qcow2 snapshot1.qcow2

# 安全地断开 backing file 链接(unsafe 模式,直接解除关联)
qemu-img rebase -u -b "" snapshot1.qcow2

4.4 快照管理

内部快照(qcow2)

内部快照将快照数据存储在同一个 qcow2 文件中:

# 离线创建快照(虚拟机关机状态)
qemu-img snapshot -l disk.qcow2  # 列出快照
qemu-img snapshot -c snap1 disk.qcow2  # 创建快照
qemu-img snapshot -a snap1 disk.qcow2  # 恢复快照
qemu-img snapshot -d snap1 disk.qcow2  # 删除快照

# 在 QEMU Monitor 中创建快照(虚拟机运行中)
# (qemu) savevm snap1
# (qemu) loadvm snap1
# (qemu) info snapshots
# (qemu) delvm snap1

外部快照

外部快照将快照存储在单独的文件中:

# 使用 qemu-img 创建外部快照
qemu-img snapshot -c snap1 -a snap1 disk.qcow2

# 使用 blockdev-add 在运行时创建外部快照
# 这通常通过 libvirt 或 QMP 来完成

详细的快照管理请参见 第 06 章 - 快照管理


4.5 备份策略

方法 1:qemu-img convert(离线备份)

# 冷备份(虚拟机关机状态)
qemu-img convert -f qcow2 -O qcow2 -c disk.qcow2 backup.qcow2

# 带压缩的备份
qemu-img convert -f qcow2 -O qcow2 -c -p disk.qcow2 backup-compressed.qcow2
# -c: 压缩
# -p: 显示进度

方法 2:快照 + dd(快速备份)

# 创建快照
qemu-img snapshot -c backup-point disk.qcow2

# 使用 dd 备份(仅备份实际使用的数据)
dd if=disk.qcow2 of=backup.dd bs=4M status=progress

# 恢复
dd if=backup.dd of=disk.qcow2 bs=4M status=progress

方法 3:增量备份

# 使用 backing chain 进行增量备份
# 只备份增量文件即可
cp snapshot1.qcow2 /backup/

# 恢复时需要整个 backing chain
# base.qcow2 + snapshot1.qcow2

方法 4:virtio-blk 块设备备份(在线备份)

# 在 QEMU Monitor 中执行块设备操作
# (qemu) drive_backup -f disk.qcow2 /backup/backup.qcow2 qcow2

# 使用 blockdev-snapshot-sync 创建外部快照后备份

备份脚本示例

#!/bin/bash
# vm-backup.sh - QEMU 虚拟机备份脚本

VM_NAME="$1"
VM_DIR="/var/lib/qemu/${VM_NAME}"
BACKUP_DIR="/backup/qemu/${VM_NAME}"
DATE=$(date +%Y%m%d_%H%M%S)
DISK="${VM_DIR}/disk.qcow2"
BACKUP="${BACKUP_DIR}/${VM_NAME}_${DATE}.qcow2"

# 检查参数
if [ -z "$VM_NAME" ]; then
    echo "用法: $0 <虚拟机名称>"
    exit 1
fi

# 创建备份目录
mkdir -p "${BACKUP_DIR}"

# 检查虚拟机是否运行中
if pgrep -f "qemu.*${VM_NAME}" > /dev/null; then
    echo "虚拟机运行中,执行在线快照备份..."
    
    # 通过 QMP 创建快照
    echo '{"execute":"qmp_capabilities"}' | \
      socat - UNIX-CONNECT:/var/run/qemu/${VM_NAME}.monitor
    
    echo "快照已创建,请通过 QMP 完成备份"
else
    echo "虚拟机关机状态,执行离线备份..."
    qemu-img convert -f qcow2 -O qcow2 -c -p \
      "${DISK}" "${BACKUP}"
fi

# 清理 30 天前的备份
find "${BACKUP_DIR}" -name "*.qcow2" -mtime +30 -delete

echo "备份完成: ${BACKUP}"

4.6 磁盘压缩

在线压缩(运行中的虚拟机)

# 在 QEMU Monitor 中执行
# (qemu) block_stream disk0  # 流式合并

离线压缩

# 方法 1:qemu-img convert 重新转换(最常用)
qemu-img convert -f qcow2 -O qcow2 -c disk.qcow2 disk-compressed.qcow2

# 方法 2:使用 zstd 压缩(QEMU 7.0+)
qemu-img convert -f qcow2 -O qcow2 \
  -o compression_type=zstd disk.qcow2 disk-zstd.qcow2

# 方法 3:fstrim(需要客户机安装 qemu-guest-agent)
# 在客户机内执行
sudo fstrim -av

压缩效果对比

# 原始 qcow2(无压缩)
qemu-img create -f qcow2 test-none.qcow2 10G

# zlib 压缩
qemu-img create -f qcow2 -o compression_type=zlib test-zlib.qcow2 10G

# zstd 压缩(更快,压缩比略低)
qemu-img create -f qcow2 -o compression_type=zstd test-zstd.qcow2 10G
压缩方式压缩速度解压速度压缩比CPU 开销
---
zlib中等
zstd中等中等

注意: 压缩会增加 CPU 开销,对 I/O 密集型虚拟机不建议使用压缩。压缩适用于归档备份场景。


4.7 磁盘扩容

扩大磁盘容量

# 扩大 qcow2 镜像(只能扩大,不能缩小)
qemu-img resize disk.qcow2 +20G

# 查看新大小
qemu-img info disk.qcow2

# 也可以设置绝对大小
qemu-img resize disk.qcow2 60G

扩展客户机分区

扩容虚拟磁盘后,还需要在客户机中扩展分区和文件系统:

方法 1:使用 growpart(推荐)

# 在客户机中执行
# 安装 growpart 工具
sudo apt install cloud-guest-utils  # Debian/Ubuntu
sudo dnf install cloud-utils-growpart  # Fedora

# 查看当前分区
lsblk

# 扩展分区(/dev/sda 的第 2 个分区)
sudo growpart /dev/sda 2

# 扩展文件系统
# ext4
sudo resize2fs /dev/sda2

# xfs
sudo xfs_growfs /

# 验证
df -h

方法 2:使用 parted

# 在客户机中执行
sudo parted /dev/sda
# (parted) print
# (parted) resizepart 2 100%
# (parted) quit

# 扩展文件系统
sudo resize2fs /dev/sda2  # ext4
sudo xfs_growfs /          # xfs

方法 3:使用 LVM

# 如果客户机使用 LVM
sudo pvresize /dev/sda2
sudo lvextend -l +100%FREE /dev/mapper/ubuntu--vg-ubuntu--lv
sudo resize2fs /dev/mapper/ubuntu--vg-ubuntu--lv

缩小磁盘(危险操作)

# QEMU 不直接支持缩小,需要转换
# 1. 先在客户机中缩小分区和文件系统
# 2. 转换到新大小的镜像

# 创建新大小的镜像
qemu-img create -f qcow2 new-disk.qcow2 20G

# 使用 virt-resize 克隆(需要 libguestfs-tools)
sudo apt install libguestfs-tools
virt-resize --shrink /dev/sda disk.qcow2 new-disk.qcow2

警告: 缩小磁盘有数据丢失风险,操作前务必做好完整备份。


4.8 qemu-nbd 网络块设备

qemu-nbd 可以将 QEMU 磁盘镜像导出为块设备,像本地磁盘一样挂载:

# 加载 nbd 内核模块
sudo modprobe nbd max_part=8

# 将 qcow2 镜像导出为块设备
sudo qemu-nbd --connect=/dev/nbd0 disk.qcow2

# 查看设备
lsblk /dev/nbd0

# 挂载分区
sudo mount /dev/nbd0p1 /mnt

# 查看文件
ls /mnt/

# 使用完毕后卸载
sudo umount /mnt
sudo qemu-nbd --disconnect /dev/nbd0
sudo modprobe -r nbd

使用 nbd 挂载 LVM 分区

# 导出镜像
sudo qemu-nbd --connect=/dev/nbd0 disk.qcow2

# 扫描 LVM 卷
sudo vgscan
sudo vgchange -ay

# 挂载 LVM 逻辑卷
sudo mount /dev/ubuntu-vg/ubuntu-lv /mnt

# 清理
sudo umount /mnt
sudo vgchange -an ubuntu-vg
sudo qemu-nbd --disconnect /dev/nbd0

使用 nbd 直接修改镜像

# 直接在镜像中编辑文件
sudo qemu-nbd --connect=/dev/nbd0 disk.qcow2
sudo mount /dev/nbd0p1 /mnt

# 修改配置文件
sudo nano /mnt/etc/hostname

sudo umount /mnt
sudo qemu-nbd --disconnect /dev/nbd0

4.9 磁盘 I/O 调优

缓存模式

缓存模式说明安全性性能
none直接 I/O,绕过宿主缓存中等
writethrough写入时同步刷新(默认)最高较低
writeback写入缓存,异步刷新中等
directsync直接 I/O + 同步最高最低
unsafe忽略所有刷新请求最高
# 使用 writeback 缓存(推荐)
qemu-system-x86_64 \
  -drive file=disk.qcow2,format=qcow2,if=virtio,cache=writeback

# 使用 none 缓存(直接 I/O)
qemu-system-x86_64 \
  -drive file=disk.qcow2,format=qcow2,if=virtio,cache=none

I/O 模型

# 使用 io_uring(Linux 5.1+,性能最好)
qemu-system-x86_64 \
  -drive file=disk.qcow2,format=qcow2,if=virtio,aio=io_uring

# 使用 native AIO
qemu-system-x86_64 \
  -drive file=disk.qcow2,format=qcow2,if=virtio,aio=native

# 使用 threads(默认)
qemu-system-x86_64 \
  -drive file=disk.qcow2,format=qcow2,if=virtio,aio=threads

I/O 性能测试

# 在虚拟机内使用 fio 测试
sudo apt install fio

# 顺序读测试
fio --name=seqread --rw=read --bs=1M --size=1G --numjobs=1 \
  --runtime=30 --time_based --filename=/tmp/fio-test

# 随机读写测试
fio --name=randrw --rw=randrw --bs=4k --size=1G --numjobs=4 \
  --runtime=30 --time_based --filename=/tmp/fio-test

要点回顾

要点核心内容
qcow2推荐格式,支持快照、压缩、加密、增量
raw性能最好,适合固定用途
backing file基础镜像 + 差异镜像,节省空间
备份离线 convert / 快照备份 / 增量备份
扩容qemu-img resize + growpart + resize2fs
qemu-nbd将镜像挂载为块设备,方便离线操作

注意事项

qcow2 vs raw 选择: 大多数场景使用 qcow2。只有在追求极致 I/O 性能且不需要快照时,才使用 raw 格式。

扩容不可逆: qemu-img resize 只能扩大不能直接缩小。缩小需要复杂的转换操作。

备份前验证: 备份完成后务必用 qemu-img check 验证备份文件的完整性。

io_uring 需要内核支持: aio=io_uring 需要 Linux 5.1+ 内核,且 QEMU 编译时启用了 liburing 支持。


扩展阅读


下一步

05 - 网络配置:深入学习 QEMU 用户模式网络、桥接、TAP、NAT 与设备直通。