在虚拟化环境中,快照功能是管理员最常用的工具之一。KVM作为Linux平台上主流的虚拟化解决方案,通过libvirt提供了完善的快照管理能力。快照本质上是对虚拟机在某个时间点的状态保存,包括磁盘状态和内存状态(可选)。根据实现方式的不同,KVM支持两种主要快照类型:
内部快照:将快照数据直接嵌入到qcow2格式的磁盘文件中,形成一个覆盖层。这种快照管理简单,但性能开销较大,特别是在频繁创建/删除时。
外部快照:创建独立的qcow2文件作为新磁盘层,原始磁盘变为只读的backing file。这种方式更灵活,支持更多磁盘类型,但需要手动管理快照链。
重要提示:libvirt官方文档明确指出,外部快照的回滚操作不受官方支持,必须通过手动方式完成。这是设计上的取舍,因为外部快照的灵活性带来了更复杂的管理需求。
内部快照依赖于qcow2格式的COW(Copy-On-Write)特性。当创建快照时:
这种设计使得单个qcow2文件可以包含多个快照点,但也会导致:
对于使用qcow2磁盘的简单虚拟机,创建和回滚内部快照的标准命令如下:
bash复制# 确保虚拟机处于关机状态(不保存内存状态)
virsh destroy mydomain
# 创建名为mysnapshot的内部快照
virsh snapshot-create-as mydomain mysnapshot \
--description "基线快照" \
--atomic
# 查看快照列表
virsh snapshot-list mydomain
# 回滚到指定快照
virsh snapshot-revert mydomain mysnapshot
关键参数说明:
--atomic:确保快照创建是原子操作,要么全部成功要么全部失败--quiesce:尝试静默客户机文件系统(需要客户机安装qemu-guest-agent)内部快照在以下场景可能出现性能问题:
优化方案:
bash复制# 定期合并快照(会生成新磁盘文件)
virsh blockcommit mydomain vda --active --wait --verbose
# 使用外部存储(如LVM)替代qcow2内部快照
lvcreate -L 10G -s -n vm_snap /dev/vg0/vm_disk
对于磁盘类型为普通文件的虚拟机,创建外部快照的基本流程:
bash复制domain="myvm"
snapshot="snap1"
target_disk="vda"
# 检查磁盘类型
virsh dumpxml $domain | grep -A5 '<disk'
# 创建外部快照(仅磁盘)
virsh snapshot-create-as $domain $snapshot \
--disk-only \
--no-metadata \
--quiesce
此时会生成新的qcow2文件(默认位于/var/lib/libvirt/images/),原始磁盘变为backing file。
由于libvirt不直接支持外部快照回滚,需要手动操作:
bash复制# 获取快照文件路径
snap_file=$(virsh domblklist $domain | grep $target_disk | awk '{print $2}')
# 获取原始磁盘路径
orig_disk=$(qemu-img info $snap_file | grep 'backing file:' | cut -d: -f2 | xargs)
# 关闭虚拟机
virsh destroy $domain
# 修改虚拟机配置指向原始磁盘
virt-xml $domain --edit target=$target_disk \
--disk path="$orig_disk" \
--update
# 删除快照文件
rm -f "$snap_file"
当虚拟机使用LVM卷、iSCSI等非文件磁盘时,需要额外步骤:
bash复制# 对于LVM卷
virsh snapshot-create-as $domain $snapshot \
--disk-only \
--diskspec vda,snapshot=external,file=/path/to/new.qcow2 \
--diskspec vdb,snapshot=no
# 回滚时需要先合并快照
virsh blockcommit $domain vda --active --pivot --wait
错误现象:
code复制error: unsupported configuration: cannot generate external snapshot name for disk 'vda' without source
解决方案:
bash复制virsh snapshot-create-as $domain $snapshot \
--disk-only \
--diskspec vda,file=/path/to/snap.qcow2
bash复制qemu-img info /path/to/disk | grep 'file format'
可能原因:
优化步骤:
bash复制# 查看当前快照链
qemu-img info --backing-chain /path/to/disk
# 合并所有快照
virsh blockpull $domain vda --wait --verbose
# 优化qcow2文件
qemu-img check -r all /path/to/disk
qemu-img convert -O qcow2 /path/to/src /path/to/dst
混合快照注意事项:
bash复制# 创建包含内存状态的快照
virsh save $domain $snapshot.save --running
# 恢复时
virsh restore $snapshot.save
建议使用脚本管理快照生命周期:
bash复制#!/bin/bash
# 自动创建带时间戳的快照
domain=$1
snapshot="auto_$(date +%Y%m%d_%H%M%S)"
virsh snapshot-create-as $domain $snapshot \
--disk-only \
--diskspec vda,snapshot=external \
--atomic
if [ $? -eq 0 ]; then
echo "快照创建成功: $snapshot"
# 保留最近3个快照
snapshots=$(virsh snapshot-list $domain --name | sort -r | tail -n +4)
for snap in $snapshots; do
virsh snapshot-delete $domain $snap --metadata
done
fi
通过libvirt事件机制监控快照操作:
python复制import libvirt
from datetime import datetime
def snapshot_callback(conn, dom, snap, event, detail, opaque):
print(f"[{datetime.now()}] 快照事件: {dom.name()}, {snap.getName()}, {event}")
conn = libvirt.open()
conn.domainEventRegisterAny(None,
libvirt.VIR_DOMAIN_EVENT_ID_SNAPSHOT,
snapshot_callback,
None)
对于关键业务虚拟机,建议采用如下策略:
bash复制# 每周全量备份
virsh dumpxml $domain > $domain_$(date +%F).xml
qemu-img convert -O qcow2 $disk $backup_dir/$domain_$(date +%F).qcow2
# 每日增量快照
virsh snapshot-create-as $domain daily_$(date +%F) \
--disk-only \
--diskspec vda,snapshot=external