如何导出最优大小的qcow2镜像文件

之前的几篇文章中介绍过如何制作OpenStack虚拟机镜像,在导出镜像文件的时候都是直接用qemu-img命令将raw格式或者qcow2格式的磁盘文件压缩后导出,相关命令如下:

1
2
3
4
5
# 将raw格式的磁盘,简单压缩并转换成qcow2格式
qemu-img convert -c -f raw ${filename}.raw -O qcow2 ${filename}.qcow2

# 将qcow2格式的磁盘,导出为简单压缩后的qcow2格式
qemu-img convert -c -f qcow2 ${filename}.raw -O qcow2 ${filename}.qcow2

不过,以上方式在不同情况下,其压缩效果差距较为明显:

情况一

  • 假如虚拟机磁盘大小为20G,刚安装好操作系统后占用1.6G,此时通过以上方式压缩导出的镜像大小可能只占1G左右甚至更小。因为磁盘的大量剩余空间还没有被使用到(大量block块都是空白的,未写入过数据),所以在导出过程中,空白的block块就会被压缩甚至忽略掉,这样导出的镜像文件的压缩效果就很不错。

情况二

  • 假如虚拟机磁盘大小为20G,在安装好操作系统后占用1.6G,然后往虚拟机里上传一个4.71G的ISO文件配置本地YUM源安装必备的一些软件,安装完成后将ISO文件删除,虚拟机内的磁盘空间显示空间已经释放出来了,磁盘占用空间变成跟操作系统刚装好时一样只有1.6G。但此时再使用以上方式压缩并导出镜像文件,会发现导出的镜像文件比之前多出了4.71G的大小。这是因为操作系统删除文件,实际只是在分区表中把文件的索引给删除了,其4.71G的物理数据还是依然占用着磁盘上的block块,这部分空间在导出过程中是无法被压缩或者忽略的(使用qemu-img info命令可以看到该磁盘文件的物理占用空间比之前变大了4.71G左右)。

针对第二种情况,我们需要在导出镜像文件前对所有未存储有效数据的block块(包括已删除文件的block块)进行置零填充,然后再进行镜像文件压缩导出。

精简导出


虚拟机内部置零填充

在虚拟机内通过dd命令创建一个全0文件,将虚拟机内的剩余可用空间全部置零,然后再将这个全0文件删除。

说明

  • 置零操作可能需要话费大量的时间,取决于剩余可用空间的大小
  • 如果虚拟机除了根分区,还将其他的如/home、/opt单独划分,记得每个分区都要执行置零操作,修改全0文件的生成路径即可
1
2
3
4
# 执行置零操作,直到提示空间不足自动退出为止
dd if=/dev/zero of=/zero.data
# 删除全0文件
rm -rf /zero.data

导出镜像文件

说明
执行导出操作前,虚拟机必须处于关机状态

针对raw格式的虚拟机磁盘文件

1
2
3
# --sparse=always稀疏拷贝,忽略全0数据
cp -a --sparse=always ${filename}.raw ${newfilename}.raw
qemu-img convert -c -f raw ${newfilename}.raw -O qcow2 ${newfilename}.qcow2

针对qcow2格式的虚拟机磁盘文件

1
qemu-img convert -c -f qcow2 ${filename}.raw -O qcow2 ${filename}.qcow2

实测导出镜像大小对比


  • raw文件实际大小(disk size):5.8G
  • 直接导出qcow2镜像大小:4.9G
  • 置零填充后导出qcow2镜像大小:636M

参考文档