从创建到回收,深入理解 qcow2 的写时复制、快照链与最佳实践
作为一名虚拟化工程师,每天与 KVM/QEMU 打交道,绕不开一个核心工具------qemu-img。它不仅是创建虚拟机磁盘的"刻刀",更是管理镜像整个生命周期(创建、快照、扩容、转换、合并、回收)的瑞士军刀。本文将系统梳理 qemu-img 管理虚拟机系统盘与数据盘镜像的常用方法,并深入剖析几个关键概念(qcow2、后端镜像、写时复制、预分配、快照链)及其相互之间的关系。
一、基础:安装与工具速览
在大部分 Linux 发行版中,qemu-img 包含在 qemu-utils 或 qemu-kvm 包中:
bash
# RHEL / CentOS
yum install qemu-img
# Ubuntu / Debian
apt install qemu-utils
qemu-img 支持 create、info、resize、convert、snapshot、check、commit 等子命令,覆盖了镜像从"生"到"灭"的全过程。
二、核心概念:你必须理解的几张"王牌"
在动手操作前,先厘清几个关键概念及其关系,这是理解生命周期管理的基石。
2.1 raw vs qcow2 -- 格式之争
| 特性 | raw | qcow2 |
|---|---|---|
| 简单直接 | 裸二进制,性能最好 | 复杂元数据,略有开销 |
| 稀疏文件 | 支持(需文件系统支持) | 原生支持 |
| 实际占用 | 始终等于虚拟大小(除非稀疏) | 仅占用实际写入大小 |
| 快照 | 不支持(需借助外部链) | 内置内部快照 + 外部差分盘 |
| 后端镜像 | 不支持 | 支持(backing file) |
| 压缩/加密 | 不支持 | 支持 |
结论 :系统盘、需快照/回滚的场景选 qcow2;追求极致 I/O 且无快照需求的数据盘可选 raw 。本文重点围绕 qcow2 展开。
2.2 写时复制 (Copy-on-Write, COW) 与后端镜像
这是 qcow2 最强大的特性。创建一个带 -b backing_file 的镜像时,新镜像(称为"差分盘"或"前端盘")只记录相对于后端镜像的变化。
- 后端镜像:通常设为"只读"的基础镜像(如安装好 OS 的模板)
- 前端镜像:可写,所有读操作先查前端,未命中则读后端;所有写操作写入前端。
关系图:
+-------------+ +-------------+
| 前端镜像A | -----> | 后端镜像 |
| (差分盘) | 依赖 | (只读模板) |
+-------------+ +-------------+
| |
+------ 链式依赖 ---------+
多个前端可以共享同一个后端,节省大量磁盘空间并加速部署。
2.3 快照链 (Snapshot Chain)
- 内部快照 :保存在同一个 qcow2 文件内,使用
qemu-img snapshot -c创建。缺点:单文件过大,删除快照不能立即释放空间。 - 外部快照 :即通过
-b创建新的差分盘,形成链:base <- snap1 <- snap2。回滚时只需更换前端文件或执行commit。
关系说明 :
后端镜像 + COW 机制 = 实现外部快照链的基础。每个差分盘本质上就是后端镜像的一个"可写快照"。
2.4 预分配 (Preallocation)
创建 qcow2 时可指定 -o preallocation=:
off(默认):稀疏文件,按需分配,创建快但首次写入有延迟。metadata:预先分配元数据(簇指针),减轻运行时元数据分配开销,推荐用于性能敏感场景(如数据库数据盘)。falloc/full:立即分配全部数据空间(falloc更快,ext4/xfs 支持)。适合需要提前占用物理空间或避免运行期扩容抖动的场景。
三、生命周期管理全流程
3.1 创建 (Create)
1. 创建一个新的空数据盘(20GB)
bash
qemu-img create -f qcow2 data01.qcow2 20G
2. 创建后端基础镜像(例如纯净系统盘)
bash
qemu-img create -f qcow2 centos7-base.qcow2 40G
# 之后使用虚拟机安装OS,完毕后保持此镜像只读
3. 基于后端镜像创建差分盘(外部快照)
bash
qemu-img create -f qcow2 -b centos7-base.qcow2 -F qcow2 vm01-system.qcow2
-b指定后端镜像-F明确指定后端格式(提高安全性)
4. 创建高性能数据盘(预分配元数据)
bash
qemu-img create -f qcow2 -o preallocation=metadata data-mysql.qcow2 100G
5. 创建加密数据盘(LUKS,推荐)
bash
qemu-img create -f qcow2 -o encryption=on,encrypt.key-secret=sec0 \
--object secret,data=MyStrongPassword,id=sec0 secret-disk.qcow2 10G
3.2 查看信息 (Info)
bash
qemu-img info vm01-system.qcow2
输出示例:
image: vm01-system.qcow2
file format: qcow2
virtual size: 40 GiB (42949672960 bytes)
disk size: 1.2 GiB
cluster_size: 65536
backing file: centos7-base.qcow2
backing file format: qcow2
Snapshot list:
ID TAG VM SIZE DATE
1 before-update 123M 2025-03-15 10:23:14
重点看 backing file 字段(表示存在后端依赖)和 Snapshot list。
3.3 调整大小 (Resize)
扩容(最常用):
bash
qemu-img resize vm-data.qcow2 +50G # 增加50G
qemu-img resize vm-data.qcow2 100G # 直接设为目标大小(必须比原大)
⚠️ 扩容后需要在虚拟机内部使用 fdisk / growpart 扩展分区,再 resize2fs(ext4)或 xfs_growfs。
缩减(极少用,高风险) :
必须先确保镜像内文件系统已缩减,再用 qemu-img resize --shrink,且强烈建议先转换后使用 --shrink 检查。
3.4 转换 (Convert)
raw → qcow2:
bash
qemu-img convert -f raw -O qcow2 disk.raw disk.qcow2
qcow2 → raw(合并后端链):
bash
qemu-img convert -f qcow2 -O raw vm01-system.qcow2 vm01-system.raw
该命令会将差分盘与后端镜像(及整条链)合并输出到一个 raw 文件。
仅合并差分盘到后端(不改变格式):
bash
qemu-img convert -f qcow2 -O qcow2 vm01-system.qcow2 merged.qcow2
带压缩的转换(节省空间):
bash
qemu-img convert -f qcow2 -O qcow2 -c vm-data.qcow2 vm-data-compressed.qcow2
-c 开启压缩,适合归档冷数据。
3.5 快照管理 (Snapshot)
内部快照(同一文件内):
bash
qemu-img snapshot -c clean_install vm01-system.qcow2 # 创建
qemu-img snapshot -l vm01-system.qcow2 # 列出
qemu-img snapshot -a clean_install vm01-system.qcow2 # 还原
qemu-img snapshot -d clean_install vm01-system.qcow2 # 删除
⚠️ 内部快照的性能和灵活性不如外部差分盘,大型生产环境更推荐外部快照。
外部快照(通过创建新差分盘实现)
假设当前运行的 active.qcow2 依赖 base.qcow2,创建快照并切换:
bash
# 1. 创建新差分盘作为当前快照
qemu-img create -f qcow2 -b active.qcow2 -F qcow2 snap1.qcow2
# 2. 之后虚拟机改用 snap1.qcow2 继续运行,active.qcow2 成为只读快照点
3.6 提交与合并 (Commit)
将差分盘的改动合并回后端镜像,简化链结构:
bash
qemu-img commit -b new-base.qcow2 diff.qcow2
或者使用 qemu-img convert 先合并再替换。
3.7 检查与修复 (Check)
bash
qemu-img check -r all trouble.qcow2
用于修复 qcow2 文件因意外关机导致的损坏。-r all 会尝试修复引用计数和泄漏簇。
3.8 回收与废弃
-
删除差分盘 :如果不再需要某个快照点,直接
rm文件即可(注意确认没有其他镜像依赖它)。 -
回收 qcow2 实际空间 :虚拟机内删除大文件后,qcow2 通常不会自动收缩。可先运行
fstrim(客户机内),然后执行:bashqemu-img convert -O qcow2 disk.qcow2 disk_shrunk.qcow2转换相当于重写一次,丢弃空闲簇。
四、典型场景最佳实践
场景1:快速部署一批开发/测试虚拟机
-
制作一个"黄金镜像"
golden.qcow2(安装好 OS 和基础软件)。 -
对每个虚拟机创建差分盘:
bashqemu-img create -f qcow2 -b golden.qcow2 -F qcow2 vm_{id}.qcow2 -
启动虚拟机,所有更改保存在各自的差分盘中,物理空间节省 80% 以上。
-
测试完毕后直接删除差分盘即可回滚到初始状态。
场景2:数据库数据盘(性能与安全)
- 创建时使用
-o preallocation=metadata减少运行时 I/O 抖动。 - 挂载
virtio驱动并启用cache=none+aio=native。 - 定期使用
qemu-img convert -c归档冷备数据盘。 - 敏感数据使用 LUKS 加密创建。
场景3:处理长时间运行的快照链
- 避免链长度超过 10 层,否则读性能会退化。
- 定期执行
qemu-img commit或convert合并链。 - 合并前关机虚拟机,或者使用
qemu-img rebase动态调整后端(高风险,需细心)。
五、概念关系总结
text
+-------------------+
| raw 格式 | (简单, 快, 无快照)
+-------------------+
|
v (convert)
+-------------------+ -b依赖 +----------------+
| qcow2 格式 | <---------------- | 后端镜像 |
+-------------------+ (写时复制) | (只读模板) |
| +----------------+
| 创建内部快照 |
v +----------------+
+-------------------+ | 差分盘1 (VM1) |
| 同一文件快照链表 | +----------------+
+-------------------+ | 差分盘2 (VM2) |
+----------------+
qemu-img snapshot -c (外部快照)
预分配 (preallocation)
+-------+--------+
| off | metadata | falloc
+-------+--------+
核心关系:
- 后端镜像 + qcow2 = 写时复制 → 差分盘(外部快照)
- 差分盘可以串成链,实现任意时间点回滚。
- 内部快照是另一个维度,保存在文件内部,适合临时备份。
- 预分配影响首次写入性能与物理空间占用。
- convert 是合并链、压缩、转换格式、回收空间的全能手段。
掌握这些概念与命令,你就能像管理代码版本一样管理虚拟磁盘的生命周期。qemu-img 虽小,却是虚拟化世界的 git------善用它,你将获得对磁盘镜像的完全掌控力。
🧠 思考题:一个虚拟机同时有内部快照和外部差分盘,提交顺序如何影响数据完整性?欢迎在评论区讨论。
本文作者 :虚拟化实践者 · 文章编号 2026-05-14
许可:自由转载,请保留出处。