You can save the minimal, compressed filesystem from a guest in a way that lets you reconstruct that filesystem (or guest) later very quickly. I’m writing an experimental tool called
virt-builder which will make this automatic, but here’s how to make the minimal, compressed filesystem manually.
I’m starting here with a freshly installed Fedora 13 i686 guest. Firstly we see what filesystems it contains:
$ virt-list-filesystems -al /dev/vg_pin/TmpF13 /dev/sda1 ext4 /dev/vg_virtbuilder/lv_root ext4 /dev/vg_virtbuilder/lv_swap swap
We have a boot partition (
/dev/sda1), a root filesystem (
/dev/vg_virtbuilder/lv_root), and a swap partition. We can just ignore swap since it doesn’t contain any information and we can reconstruct it at will.
There is also some extra information “hidden” in the disk and not in a partition, namely the boot sector, partition table, and (maybe) GRUB stages. For this guest just the boot sector is interesting, other guests may have a boot loader located between the boot sector and the first partition. I’m going to ignore these for now, although virt-builder will need to restore this in order to make a bootable guest.
Let’s grab the boot and root partitions using guestfish:
$ guestfish --ro -i -a /dev/vg_pin/TmpF13 \ download /dev/sda1 fedora-13-i686-boot.img $ guestfish --progress --ro -i -a /dev/vg_pin/TmpF13 \ download /dev/vg_virtbuilder/lv_root fedora-13-i686-root.img 100% ⟦▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉⟧ 00:00
The boot partition is small enough that I’m just going to leave it as it is for now. But I need to shrink the root filesystem. The reason is that I might want to restore this to a different-sized, possibly smaller guest than the one I just created. There is only about 2GB of data in the root filesystem, but as an ext4 filesystem it is taking up about 6GB of space. The resize2fs command has a handy -M option which makes this very simple:
$ e2fsck -f fedora-13-i686-root.img e2fsck 1.41.12 (17-May-2010) Pass 1: Checking inodes, blocks, and sizes Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information Fedora-13-i686-L: 91151/368640 files (0.1% non-contiguous), 531701/1458176 blocks $ resize2fs -M fedora-13-i686-root.img resize2fs 1.41.12 (17-May-2010) Resizing the filesystem on fedora-13-i686-root.img to 520344 (4k) blocks. The filesystem on fedora-13-i686-root.img is now 520344 blocks long.
Note that new size: 520344 x 4k blocks = 2081376k. We can therefore truncate the file down to the new size without any loss of information:
$ truncate -s 2081376k fedora-13-i686-root.img $ ls -lh total 2.5G -rw-rw-r--. 1 rjones rjones 500M Oct 30 10:21 fedora-13-i686-boot.img -rw-rw-r--. 1 rjones rjones 2.0G Oct 30 10:30 fedora-13-i686-root.img
I haven’t finished yet. I now need to compress both filesystems so I have something small(ish) and portable. I performed some tests, and xz was the clear winner in terms of final compressed size, although it does take a very long time to run with the -9 option.
$ xz -9 *.img $ ls -lh total 652M -rw-rw-r--. 1 rjones rjones 250M Oct 30 10:21 fedora-13-i686-boot.img.xz -rw-rw-r--. 1 rjones rjones 403M Oct 30 10:30 fedora-13-i686-root.img.xz
From the two files above, plus the boot sector stuff that I glossed over, it is possible to reconstruct a Fedora 13 VM of any dimensions quickly (in about 1 minute 15 seconds on my machine). Note the comments are not part of the command, and the guest is fully bootable:
guestfish -x -- \ # create a disk image of any size alloc test.img 10G : \ run : \ # create the partitions part-init /dev/sda mbr : \ part-add /dev/sda primary 2048 1026047 : \ part-add /dev/sda primary 1026048 -64 : \ # upload the boot loader upload fedora-13-i686-grub.img /dev/sda : \ # upload the boot partition upload <( xzcat fedora-13-i686-boot.img.xz ) /dev/sda1 : \ # create the logical volumes for root and swap pvcreate /dev/sda2 : \ vgcreate vg_virtbuilder /dev/sda2 : \ lvcreate lv_swap vg_virtbuilder 512 : \ lvcreate lv_root vg_virtbuilder 256 : \ lvresize-free /dev/vg_virtbuilder/lv_root 100 : \ # make fresh swap mkswap /dev/vg_virtbuilder/lv_swap : \ # upload and resize the root filesystem upload <( xzcat fedora-13-i686-root.img.xz ) /dev/vg_virtbuilder/lv_root : \ resize2fs /dev/vg_virtbuilder/lv_root