ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

qemu-img 完全指南:虚拟机磁盘镜像创建、转换与扩容实战手册

qemu-img 完全指南:虚拟机磁盘镜像创建、转换与扩容实战手册 玩虚拟化的人迟早会撞上qemu-img这面墙。不管你是用 KVM、Proxmox VE 还是单纯想在本地跑个 QEMU 虚拟机磁盘镜像的创建、转换、扩容、快照最终都会落到这个命令行工具上。它不像图形界面那么直观但恰恰是这种“丑”和“硬”让它在脚本化运维和批量处理时异常可靠。这篇文章不是照搬 man page我把自己在实际操作中反复用到的命令、踩过的坑和几个完整的处理案例整理了一份手册新老手都能在里面找到点东西。1. 入手之前qemu-img 到底解决什么问题1.1 虚拟磁盘镜像是什么什么时候需要 qemu-img先说说最基础的概念。虚拟机里的硬盘不是一块真实的物理磁盘而是一个文件这个文件就是“磁盘镜像”。按照格式不同它可能是厚厚的一块完整空间也可能是一个只记录实际写入数据、随用随长的瘦文件。qemu-img就是用来操作这批文件的瑞士军刀创建、转换格式、查看信息、检查一致性、扩容缩小、管理快照全部由它包办。什么时候你一定会用到它举几个典型场景刚装完一台 CentOS 虚拟机想把 qcow2 转换成 raw 格式以便做物理机迁移磁盘分区快满了想在不破坏数据的前提下给虚拟机硬盘增加 20G 空间拿同一块基础镜像批量克隆几台测试机或者只是单纯想知道那块 qcow2 文件为什么比预想的大很多。这些操作如果不用qemu-img就得借助商业虚拟化平台或者折腾 GUI 工具效率低不少。1.2 安装与基础准备多数 Linux 发行版默认不自带qemu-img但它通常会随 QEMU 组件一起安装。Debian/Ubuntu 上执行apt install qemu-utils -yCentOS/RHEL 系则是yum install qemu-img -y装完之后先验证一下版本不同版本在某些参数行为上略有差异qemu-img --version我建议你先建一个干净的实验目录准备一块 1G 左右的测试镜像后面所有命令都能在上面练手。用 root 或对目录有写权限的普通用户操作都可以但要注意后续如果要挂载或转换系统盘通常需要 root 权限。2. 镜像创建从命令行到一块真实磁盘2.1 三种主流镜像格式的特性对比qemu-img支持很多格式raw、qcow2、qed、vmdk、vhdx、vdi、luks 等。但日常用得最多、最值得深入理解的就是 raw 和 qcow2 两种vmdk 则常见于 VMware 互操作场景。raw 格式最直接它就是把虚拟磁盘按字节展开成一个大文件没有额外元数据。优点是性能好、无需转换即可被很多工具直接读取缺点是占用空间大、不支持快照等高级特性。qcow2QEMU Copy On Write version 2是目前 KVM 环境的绝对主流它支持写时复制、快照、压缩、AES 加密、backing file差异镜像等特性文件体积通常远小于虚拟磁盘大小但伴随而来的是略微的性能开销。vmdk 是 VMware 的格式qemu-img也能读写常用于混合虚拟化环境迁移vhdx 是 Hyper-V 格式跨平台迁移时会接触到。如果你没有特殊迁移需求我不建议在 QEMU/KVM 环境里用 vmdk 或 vhdx 作为主力格式兼容性和高级特性支持终归不如 qcow2 来得完整。2.2 创建镜像的完整命令与参数选择创建一块 qcow2 格式、大小为 10G 的镜像qemu-img create -f qcow2 disk.qcow2 10G这一句执行完你得到的大小并不是 10G而是一个可能只有 193K 的稀疏文件。qcow2 是按需分配的只有虚拟机真正写入时才在宿主文件系统上占用块。你可以用ls -lh看表象大小用du -h看实际占用两者会存在明显差异。如果想一开始就预留全部空间防止后续写入时因宿主机磁盘不足导致 IO 错误可以加 preallocation 参数qemu-img create -f qcow2 -o preallocationfull disk-full.qcow2 10Gfull 预分配会立即占用 10G适合对性能敏感的生产虚拟机metadata 预分配只把 qcow2 的元数据预留出来文件稍大但创建速度快适合大批量创建实例时折中使用。raw 格式则不一样它默认就是完整空间除非你用truncate之类的命令创建稀疏文件。创建 raw 格式qemu-img create -f raw disk.raw 10G这块 raw 文件会立即显示为 10G但如果底层文件系统支持稀疏文件实际占用的可能也只是少量块后续写入时才逐渐增大。这个特性有时候挺迷惑人检查磁盘占用量时务必用du而不是ls。2.3 预分配模式的性能差异经常有人问qcow2 加了 full 预分配之后性能和 raw 还有多大差距我的实测感受是裸设备或者 raw 格式在顺序读写上确实略微领先但 qcow2 在引入了cachenone和iothread之类的优化后差距已经缩小到很难感知的程度尤其在磁盘本身是 SSD 的情况下。从运维角度来说我更看重的是完整预分配带来的空间确定性。生产环境最怕的不是慢而是虚拟机在深夜突然写入大量数据时发现宿主机目录满了那种 IO 错误会导致虚拟机文件系统切换到只读模式比慢更致命。所以重要业务我通常创建 qcow2 并加上preallocationmetadata既保留一定的按需分配灵活性又趁早把元数据结构固定下来。3. 镜像转换与格式迁移qcow2 与 raw 的取舍3.1 convert 命令的标准用法格式转换是qemu-img最高频的场景之一。把 qcow2 转成 rawqemu-img convert -f qcow2 -O raw disk.qcow2 disk.raw-f指定源格式-O指定目标格式-O大写这是新手最容易踩的坑。小写-o是传给目标格式的选项参数作用完全不同。如果省略-fqemu-img会尝试自动检测如果省略-O默认输出格式也是 raw。为了安全和明确我习惯每次都把这两个参数显式写出来。转换过程中有一个细节值得注意convert默认只拷贝实际有数据的块目标 raw 文件会是一个稀疏文件。如果你希望转换后的 raw 文件完整占用所有空间可以加-S 0参数它表示所有扇区都视为“需要分配”这样目标文件就不会有稀疏特性。3.2 压缩与优化让镜像瘦下来qcow2 转 qcow2 的常见误区是直接拷贝文件这样不仅没有优化反而可能把碎片和冗余块一起拷贝过去。正确姿势是用 convert 做一次重写同时加上压缩qemu-img convert -f qcow2 -O qcow2 -c old.qcow2 new.qcow2-c参数开启压缩。压缩效果取决于镜像内部数据的特征我的经验是装完系统加常用软件后未做大量碎片写入的镜像压缩率通常能到 20% 到 30%如果是数据密集型比如放满日志和数据库文件的镜像压缩收益会更大。需要说明的是convert不会保留源镜像的快照和 backing file 链信息。如果你有一块带快照的 qcow2执行 convert 时会得到一个平面化的镜像也就是把所有快照差异合并进底层数据这通常正是你想要的“摊平”操作。但如果你希望保留快照结构就别用 convert老老实实复制文件。3.3 格式选型建议我给自己定过一条选型原则长期保留的基础镜像用 qcow2需要直通或跨平台导出的镜像用 raw涉及到要搬到公有云或物理机直接引导的场景才考虑 vmdk/vhdx。新项目一律 qcow2因为你永远不知道后续会不会需要快照或者差异镜像。转换过程本身一般很稳但有两个前提一是源镜像不能在转换过程中被正在运行的虚拟机写入否则可能得到损坏的镜像二是目标分区要有足够空间虽然 convert 通常不占用完整目标大小但如果目标格式是预分配的峰值空间会非常大。我在一次 vmdk 转 raw 时源文件只有 40G转的目标 raw 文件却瞬间占了 40G宿主机余量不够直接失败教训深刻。4. 镜像检修与信息核验别让隐患积累4.1 info 命令的实用参数解读给虚拟机做体检第一件事就是查镜像信息qemu-img info disk.qcow2输出会显示 format格式、virtual size虚拟大小、disk size实际占用、cluster_size簇大小等。如果镜像有 backing file差异镜像输出里会多一行backing file后面跟着父镜像的路径。批量查看信息可以加--outputjson方便脚本解析qemu-img info --outputjson disk.qcow2有一个容易被忽略的信息disk size通常只统计当前文件实际占用但对于稀疏文件不同文件系统报告的数值可能不一致。我习惯同时用qemu-img info和du -h交叉验证尤其在判断“镜像是否异常膨胀”时这两个数字的差异能说明很多问题。4.2 check 命令检查与修复镜像文件在宿主机异常断电或宿主机磁盘损坏时可能出现内部元数据不一致。qcow2 有自检机制跑一遍qemu-img check disk.qcow2它会扫描镜像内所有表项、refcount引用计数和快照信息输出错误数。如果发现有 leaked clusters泄漏簇或 corruptions损坏项可以尝试qemu-img check -r all disk.qcow2-r all表示尝试修复所有可修复的问题。但我必须提醒一句check -r修复的是“镜像文件自身的一致性”不是虚拟机内部文件系统的完整性。万一镜像内部元数据修复后虚拟机里看到的文件系统可能还是需要 fsck 的。我处理过一次 qcow2 因宿主断电而报“Cannot get block status”的问题-r all跑完后镜像能重新挂载但里面一个 ext4 分区还是需要进救援模式 fsck 才能正常启动。把check做成定期巡检任务是个好习惯。线上虚拟化环境我一般用 cron 每周跑一次脚本记录所有 qcow2 的 check 输出一旦出现非零错误就立刻介入。镜像是虚拟机的唯一持久化载体小问题积累成不可修复的大问题时代价远超巡检的那点开销。4.3 实际案例定位一块无法启动的虚拟机磁盘有次一台测试虚拟机重启后起不来virsh list --all显示为 running但 QEMU 进程反复崩溃。我先执行qemu-img info /data/vm/disk.qcow2发现 virtual size 正常但 disk size 比之前明显小了很多立刻意识到文件可能截断了。qemu-img check报了一堆 cluster 错误和 refcount 错误用-r all修复后表面通过但虚拟机仍然无法启动。最后检查宿主机物理磁盘时发现该目录所在分区已经满了再查看 inode 和空间输出通过清理日志与导出镜像才恢复正常。这个案例给我的教训是镜像问题往往不是镜像自己的问题而是宿主环境的延伸体现。接到镜像损坏的信号第一反应可以查工具第二反应必须查宿主机磁盘空间和文件系统健康度。5. 镜像扩容、快照与高级玩法5.1 resize给磁盘扩容虚拟机磁盘不够用是最常见的需求。qcow2 扩容qemu-img resize disk.qcow2 20G执行完镜像的 virtual size 变大了但虚拟机内部的分区和文件系统并不知道这块新空间还需要进系统处理。如果是 Linux 的 virtio 磁盘通常用growpart扩展分区再用resize2fs扩展文件系统。比如磁盘设备名是/dev/vda分区 2 是根分区growpart /dev/vda 2 resize2fs /dev/vda2这里有个顺序问题先扩展镜像再扩展分区最后扩展文件系统。反过来操作没有任何意义。Windows 虚拟机则需要从磁盘管理里直接“扩展卷”。扩容只能增大不能缩小吗qemu-img resize也支持缩小但需要先缩小虚拟机内部文件系统和分区再缩小镜像中间一丁点差错都会造成数据损失。我强烈建议不要轻易缩小 qcow2除非你做了完整快照且验证过可恢复。raw 镜像缩小则要记得先转换否则需借助truncate操作风险更高。扩展之后确认一下新镜像尺寸方法很简单直接看info的 virtual size 字段即可。5.2 快照管理snapshot 命令实战qcow2 内建快照是它最值钱的能力之一。创建快照qemu-img snapshot -c before-upgrade disk.qcow2查看快照列表qemu-img snapshot -l disk.qcow2回滚到某个快照qemu-img snapshot -a before-upgrade disk.qcow2删除快照qemu-img snapshot -d before-upgrade disk.qcow2快照的底层原理是写时复制创建快照后原镜像所有新写入的数据会记录到快照差异区域原数据块则保留下来用于恢复。这意味着快照创建后镜像的 disk size 会持续增长尤其在高写入负载下。快照使用有几个硬性经验第一快照不是备份宿主文件系统损坏时快照同样跟着遭殃第二快照链越长读写性能劣化越明显我一般控制在三层以内完成状态验证后的临时快照会及时删除第三不要在快照存在的情况下直接用qemu-img convert做迁移会得到平面化结果如果这不是你的目的会有很大隐患。5.3 rebase 与 bitmap被低估的两个功能rebase 是配合 backing file 使用的高级操作。差异镜像overlay依赖一个基础镜像rebase 可以把差异镜像的底层基础替换成另一个或者在基础镜像被更新后把差异合并到新的基础上qemu-img rebase -b new-base.qcow2 overlay.qcow2不加-u时rebase 会执行实际的数据重写这是一个耗时操作。如果只需要修改 backing file 的路径记录而保持数据不动可以加-uunsafe模式。但只有在确认新旧底座差异不影响数据时才建议这么做否则很容易出现逻辑错位。bitmap位图是 qemu 增量备份的关键机制。给镜像创建一个持久位图qemu-img bitmap --add disk.qcow2 backup-bitmap之后用qemu-img map查看区块映射就能知道哪些块被写过。这个功能配合 libvirt 的增量备份接口可以做到有效的备份容灾。日常小环境不一定用得上但了解存在总比临时抓瞎好。6. 常见问题与排查技巧实录6.1 镜像大小异常qcow2 显示比想象中大得多跑了一段虚拟机后qcow2 文件从几 G 涨到几十 G这是写入量大的正常情况但如果清理了大量数据后文件仍不缩小就有问题了。qcow2 的典型特点是“只增不减”删除文件只释放内部虚拟块不会自动把物理空间返还给宿主机。解决办法就是做一次流式转换qemu-img convert -f qcow2 -O qcow2 disk.qcow2 compacted.qcow2如果同时有多个虚拟机注意分批操作转换期间磁盘 IO 会比较高。6.2 权限错误与格式误判最常见的低级错误执行qemu-img命令时遇到Permission denied多数情况下不是工具问题而是镜像文件的所有者与当前执行用户不一致。虚拟机镜像通常属于 qemu 用户或者 root用普通用户操作时需要 sudo或者提前chown修改属主。还有一种情况是目录本身没有写权限转换目标文件写不进去。格式误判也很常见你把一个 qcow2 文件重命名为 .raw然后用-f raw去读结果报错。qemu-img不会根据扩展名自动识别格式必须显式指定正确的-f不确定时先跑qemu-img info自动检测。6.3 其他典型问题速查表问题现象可能原因推荐处理方式qemu-img: Could not open镜像路径错误或格式指定错误用qemu-img info检测确认-f参数虚拟机启动卡在引导阶段镜像损坏或快照链断裂qemu-img check必要时-r allresize 后虚拟机看不到新空间只扩了镜像未扩分区和文件系统进系统用growpart、resize2fs或 Windows 磁盘管理扩展卷转换中报No space left目标分区空间不足清理宿主机空间或换到更大的目标目录镜像 check 提示 leaked clusters上次异常退出未完全清理先备份再check -r allsnapshot 后镜像文件膨胀迅速快照写时复制机制导致及时删除无用快照避免长期保活排查顺序我基本固定为先info确认识别信息再check确认健康度再考虑转换或修复。不要一上来就-r all修复动作本身是有副作用的备份过再修更稳妥。另外提一个细节qemu-img操作大镜像时如果宿主文件系统是 btrfs建议先确认是否开启了 CoW。btrfs 默认对文件做写时复制镜像本身又是高频写文件叠加 CoW 会造成大量空间碎片和性能损耗。用chattr C关闭镜像文件所在的目录或文件的 CoW 特性是 btrfs 上跑 KVM 的一个重要优化点。最后再分享一个我最近常干的事用qemu-img convert结合 systemd timer 做每周一次的镜像“压缩保洁”。因为测试环境有大量临时虚拟机删除后基础镜像不回收空间每周自动转换一次把没有实际数据的空洞全部清掉宿主机磁盘空间稳定多了。qemu-img就是这样命令本身不难难的是你得知道在什么时机、用什么组合拳去处理镜像的真实状态。工具是死的用法是活的多在你的环境里跑几轮它就能从“一个命令行工具”变成“你管理虚拟化环境最靠谱的右手”。
返回列表