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

QEMU 虚拟化完全指南 / 06 - 快照管理

06 - 快照管理

全面掌握 QEMU 内部快照、外部快照、实时快照的创建、恢复、管理与自动化。


6.1 快照概念

QEMU 支持两种快照方式:内部快照外部快照。理解它们的区别是正确使用快照的关键。

快照类型对比

特性内部快照外部快照
存储位置同一个 qcow2 文件内独立的外部文件
格式仅 qcow2任意格式
离线创建
在线创建✅ (QEMU Monitor)✅ (QMP/libvirt)
磁盘空间增量占用创建新的差异文件
恢复速度中等
删除快照释放空间合并后释放
链式管理backing chain
性能影响快照越多越慢链越长越慢

6.2 内部快照

离线操作(qemu-img)

# 查看快照列表
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-img snapshot -l disk.qcow2 | awk 'NR>2 {print $2}' | while read snap; do
    qemu-img snapshot -d "$snap" disk.qcow2
done

在线操作(QEMU Monitor)

# 启动 QEMU 并启用 Monitor
qemu-system-x86_64 \
  -enable-kvm -cpu host -m 4G \
  -drive file=disk.qcow2,format=qcow2 \
  -monitor stdio

在 Monitor 中执行:

# 创建快照
(qemu) savevm snap-before-update

# 查看快照列表
(qemu) info snapshots
ID        TAG                 VM SIZE  DATE       VM CLOCK
1         snap-before-update  256M     2026-05-10 10:30:00  00:15:23.456
2         snap-clean          128M     2026-05-10 09:00:00  00:05:12.789

# 恢复快照
(qemu) loadvm snap-before-update

# 删除快照
(qemu) delvm snap-before-update

使用 QMP(QEMU Machine Protocol)

# 通过 QMP Socket 交互
qemu-system-x86_64 \
  -enable-kvm -cpu host -m 4G \
  -drive file=disk.qcow2,format=qcow2 \
  -qmp unix:/tmp/qemu.sock,server,nowait

# 使用 socat 发送 QMP 命令
echo '{"execute":"qmp_capabilities"}' | socat - UNIX-CONNECT:/tmp/qemu.sock

# 创建快照
echo '{"execute":"blockdev-snapshot-sync","arguments":{"node-name":"drive0","snapshot-file":"disk.snap.qcow2","snapshot-name":"snap1"}}' | socat - UNIX-CONNECT:/tmp/qemu.sock

6.3 外部快照

外部快照将快照存储在单独的文件中,通过 backing chain 建立层级关系:

外部快照的 backing chain:
  原始: disk.qcow2 (base)
     ├── 快照后: disk-snap1.qcow2 (新写入的数据)
     │            └── backing: disk.qcow2
     └── 快照后: disk-snap2.qcow2
                  └── backing: disk-snap1.qcow2
                              └── backing: disk.qcow2

创建外部快照

# 方法 1:使用 qemu-img
qemu-img snapshot -c -a snap1 disk.qcow2

# 方法 2:在 QMP 中使用 blockdev-snapshot-sync
# (在运行中的虚拟机上操作)

# 方法 3:使用 qemu-img rebase
# 先创建新文件
qemu-img create -f qcow2 -b disk.qcow2 -F qcow2 disk-snap1.qcow2

# 使用新文件启动
qemu-system-x86_64 ... -drive file=disk-snap1.qcow2,format=qcow2

在线外部快照(QMP)

# 通过 QMP 创建外部快照
cat << 'EOF' | socat - UNIX-CONNECT:/tmp/qemu.sock
{"execute":"qmp_capabilities"}

{"execute":"blockdev-snapshot-sync","arguments":{
    "node-name":"drive0",
    "overlay-node-name":"overlay0",
    "overlay-file":"disk-snap1.qcow2",
    "overlay-format":"qcow2",
    "snapshot-name":"snap1"
}}
EOF

合并外部快照

# 将快照数据合并回基础镜像
qemu-img commit disk-snap1.qcow2

# 或者使用 block-commit(在线合并)
# (qemu) block-commit drive0

# 将所有层合并为一个独立文件
qemu-img convert -f qcow2 -O qcow2 disk-snap1.qcow2 disk-merged.qcow2

6.4 实时快照(Live Snapshot)

实时快照在虚拟机运行状态下创建,不会中断服务:

使用 libvirt 实时快照

# 创建实时快照
virsh snapshot-create-as ubuntu-vm \
  --name "live-snap1" \
  --description "Before update" \
  --atomic

# 查看快照
virsh snapshot-list ubuntu-vm

# 恢复快照
virsh snapshot-revert ubuntu-vm live-snap1

# 删除快照
virsh snapshot-delete ubuntu-vm live-snap1

QMP 实时快照命令

# 创建外部快照(推荐方式)
echo '{"execute":"blockdev-snapshot-sync","arguments":{"node-name":"drive0","snapshot-file":"snap.qcow2","snapshot-name":"live-snap","format":"qcow2"}}' | socat - UNIX-CONNECT:/tmp/qemu.sock

6.5 快照恢复策略

恢复到指定快照

# 离线恢复(虚拟机关机状态)
qemu-img snapshot -a snap1 disk.qcow2

# 在线恢复(Monitor)
# (qemu) loadvm snap1

# 使用 libvirt
virsh snapshot-revert vm-name snap-name

部分恢复(仅恢复单个磁盘)

# 当虚拟机有多个磁盘时,可能只需要恢复其中一个
# 使用 block-stream 或 block-commit 恢复特定磁盘

# 在 Monitor 中
# (qemu) block-commit disk0 base

快照恢复注意事项

场景操作风险
离线恢复qemu-img snapshot -a
在线恢复loadvm中等(内存状态恢复)
链式快照恢复需要完整 backing chain高(链断裂会导致数据丢失)

6.6 快照管理最佳实践

命名规范

# 推荐的快照命名格式: <用途>-<日期>-<说明>
qemu-img snapshot -c pre-update-20260510-app-upgrade disk.qcow2
qemu-img snapshot -c daily-20260510-0300 disk.qcow2
qemu-img snapshot -c pre-migration disk.qcow2

快照清理策略

#!/bin/bash
# snapshot-cleanup.sh - 清理过期快照

DISK="disk.qcow2"
KEEP_DAYS=7

# 列出所有快照
snaps=$(qemu-img snapshot -l ${DISK} | awk 'NR>2 {print $2}')

for snap in $snaps; do
    # 提取日期(假设格式中包含 YYYYMMDD)
    date_str=$(echo "$snap" | grep -oP '\d{8}' | head -1)
    
    if [ -n "$date_str" ]; then
        snap_date=$(date -d "$date_str" +%s)
        cutoff_date=$(date -d "-${KEEP_DAYS} days" +%s)
        
        if [ "$snap_date" -lt "$cutoff_date" ]; then
            echo "删除过期快照: $snap"
            qemu-img snapshot -d "$snap" "$DISK"
        fi
    fi
done

快照与备份结合

#!/bin/bash
# 基于快照的增量备份

VM_DISK="disk.qcow2"
BACKUP_DIR="/backup"
SNAP_NAME="backup-$(date +%Y%m%d-%H%M%S)"

# 创建快照
qemu-img snapshot -c "${SNAP_NAME}" "${VM_DISK}"

# 备份快照(可以使用 rsync 增量传输)
rsync -av --progress "${VM_DISK}" "${BACKUP_DIR}/"

# 保留最近 7 个快照
qemu-img snapshot -l "${VM_DISK}" | awk 'NR>2 {print $2}' | \
  sort -r | tail -n +8 | while read snap; do
    echo "清理旧快照: $snap"
    qemu-img snapshot -d "$snap" "${VM_DISK}"
done

6.7 快照故障排查

常见问题

问题原因解决方案
快照创建失败磁盘空间不足清理空间或使用外部快照
恢复后数据丢失覆盖了快照后的数据恢复前先备份当前状态
backing chain 断裂中间层被删除使用 qemu-img rebase 修复
快照文件损坏异常断电使用 qemu-img check 检查

修复 backing chain

# 检查 backing chain 完整性
qemu-img info --backing-chain disk-snap3.qcow2

# 如果中间层丢失,可以手动指定新的 backing file
qemu-img rebase -b disk-snap1.qcow2 -F qcow2 disk-snap3.qcow2

# 强制断开 backing chain(创建独立副本)
qemu-img convert -f qcow2 -O qcow2 disk-snap3.qcow2 disk-flat.qcow2

6.8 自动化快照管理

定时快照脚本(cron)

#!/bin/bash
# /usr/local/bin/qemu-snapshot-auto.sh

VM_NAME="$1"
ACTION="$2"  # create, list, restore, delete
SNAP_NAME="$3"
VM_DISK="/var/lib/qemu/${VM_NAME}/disk.qcow2"
LOG="/var/log/qemu-snapshot.log"

log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG}"
}

case "${ACTION}" in
    create)
        SNAP="${SNAP_NAME:-auto-$(date +%Y%m%d-%H%M%S)}"
        qemu-img snapshot -c "${SNAP}" "${VM_DISK}" 2>&1
        log "创建快照: ${VM_NAME} -> ${SNAP}"
        
        # 保留最近 24 个快照(每天一个,保留一个月的)
        MAX_SNAPS=24
        qemu-img snapshot -l "${VM_DISK}" | awk 'NR>2 {print $2}' | \
          sort -r | tail -n +$((MAX_SNAPS + 1)) | while read snap; do
            qemu-img snapshot -d "$snap" "${VM_DISK}"
            log "清理旧快照: ${VM_NAME} -> ${snap}"
        done
        ;;
    list)
        qemu-img snapshot -l "${VM_DISK}"
        ;;
    restore)
        if [ -z "${SNAP_NAME}" ]; then
            echo "用法: $0 <vm> restore <snapshot>"
            exit 1
        fi
        qemu-img snapshot -a "${SNAP_NAME}" "${VM_DISK}" 2>&1
        log "恢复快照: ${VM_NAME} -> ${SNAP_NAME}"
        ;;
    delete)
        if [ -z "${SNAP_NAME}" ]; then
            echo "用法: $0 <vm> delete <snapshot>"
            exit 1
        fi
        qemu-img snapshot -d "${SNAP_NAME}" "${VM_DISK}" 2>&1
        log "删除快照: ${VM_NAME} -> ${SNAP_NAME}"
        ;;
    *)
        echo "用法: $0 <vm> {create|list|restore|delete} [snapshot-name]"
        exit 1
        ;;
esac

cron 定时任务

# 每天凌晨 3 点创建快照
0 3 * * * /usr/local/bin/qemu-snapshot-auto.sh ubuntu-vm create

# 每周日凌晨 4 点创建周快照
0 4 * * 0 /usr/local/bin/qemu-snapshot-auto.sh ubuntu-vm create weekly-$(date +\%Y\%m\%d)

要点回顾

要点核心内容
内部快照数据存在同一文件中,离线/在线均可使用
外部快照差异文件独立存储,通过 backing chain 关联
实时快照虚拟机运行中创建,不中断服务
恢复策略离线用 qemu-img,在线用 Monitor/QMP
自动化cron + 脚本实现定时快照与清理

注意事项

快照不是备份: 快照依赖基础磁盘文件,如果基础文件损坏,所有快照都会丢失。快照应与独立备份结合使用。

快照性能影响: 内部快照会增大 qcow2 文件体积,外部快照会增加 I/O 路径长度。建议控制快照数量(不超过 10-20 个)。

在线快照一致性: 在线创建快照时,建议先使用 guest agent 冻结文件系统,确保数据一致性。


扩展阅读


下一步

07 - 虚拟机迁移:学习在线迁移、离线迁移、跨主机迁移与共享存储方案。