virt-builder can throw out new virtual machines with existing operating systems in a few seconds, and you can also write these directly to a USB key or hard disk:
# virt-builder fedora-20 -o /dev/sdX
What you’ve not been able to do is create a bootable CD-ROM or ISO image.
For that I was using the awful livecd-creator program. This needs root and is incredibly fragile. You can have a kickstart that works one day, but not the next, and requires massive hacks to get working … which is the exact reason why I set off to find out how to make virt-builder create ISOs.
The background as to why this is difficult: CDs are not writable.
You can take all the files from a Fedora guest built by virt-builder and turn them into an ISO, and put ISOLINUX on it but such a guest would not be able to boot, or at least, it would fail the first time it tried to write to the disk. One day overlayfs (which just went upstream a few days ago) will solve this, but until that is widely available in upstream kernels, we’re going to need something that creates a writable overlay at boot time.
I have chosen dracut (another tool I have a love/hate, mainly hate, relationship with), which has a useful module called dmsquash-live. This implements the boot side of making a live CD writable, for Fedora and RHEL. It’s what livecd-creator uses.
It requires that we have a filesystem containing a squashfs in a particular location on the CD:
That squashfs has to contain inside it a disk image with this precise name:
and the disk image is the root filesystem.
The script below creates all of this, and effectively replaces livecd-creator with something manageable that doesn’t require root, and is only 100 lines of shell (take that OO/Python!)
Once you’ve run the script you can try booting the image using:
$ qemu-kvm -m 2048 -cdrom boot.iso -boot d
One improvement to this script would be to remove the dependency on dmsquash-live. We don’t need the baroque complexity of this script, and could write a custom dracut module (perhaps even, a tiny self-contained initramfs) which would do what we need. It could even use overlayfs to simplify things greatly.
#!/bin/bash - set -e # Make bootable ISO from virt-builder # image. # # This requires the Fedora # squashfs/rootfs machinery. See: # /lib/dracut/modules.d/90dmsquash-live/dmsquash-live-root.sh cd /tmp # Build the regular disk image, but also # build a special initramfs which has # the dmsquash-live & pollcdrom modules # enabled. We also need to kill SELinux # relabelling, and hence SELinux. cat > postinstall <<'EOF' #!/bin/bash - version=` rpm -q kernel | sort -rV | head -1 | sed 's/kernel-//' ` echo installed kernel version: $version dracut --no-hostonly --add "dmsquash-live pollcdrom" /boot/initrd0 $version EOF virt-builder fedora-20 \ --install kernel \ --root-password password:123456 \ --edit '/etc/selinux/config: s/SELINUX=enforcing/SELINUX=disabled/' \ --delete /.autorelabel \ --run postinstall # Extract the root filesystem (as an ext3/4 disk image). guestfish --progress-bars --ro -a fedora-20.img -i \ download /dev/sda3 rootfs.img # Update /etc/fstab in the rootfs (but NOT in the original guest) # so it works for the CD virt-customize -a rootfs.img \ --write '/etc/fstab:/dev/root / ext4 defaults 1 1' # Turn the rootfs.img into a squashfs # which must contain the layout # /LiveOS/rootfs.img rm -rf CDroot rm -f squashfs.img mkdir -p CDroot/LiveOS mv rootfs.img CDroot/LiveOS mksquashfs CDroot squashfs.img # Create the CD layout. rm -rf CDroot mkdir -p CDroot/LiveOS cp squashfs.img CDroot/LiveOS/ mkdir CDroot/isolinux # Get the kernel (only) from the disk # image. pushd CDroot/isolinux virt-builder --get-kernel ../../fedora-20.img mv vmlinuz* vmlinuz0 rm init* popd # Get the special initrd that we built # above. guestfish --ro -a fedora-20.img -i \ download /boot/initrd0 CDroot/isolinux/initrd0 # ISOLINUX configuration. cat > CDroot/isolinux/isolinux.cfg <<EOF prompt 1 default 1 label 1 kernel vmlinuz0 append initrd=initrd0 rd.live.image root=CDLABEL=boot rootfstype=auto rd.live.debug console=tty0 rd_NO_PLYMOUTH EOF # Rest of ISOLINUX installation. cp /usr/share/syslinux/isolinux.bin CDroot/isolinux/ cp /usr/share/syslinux/ldlinux.c32 CDroot/isolinux/ cp /usr/share/syslinux/libcom32.c32 CDroot/isolinux/ cp /usr/share/syslinux/libutil.c32 CDroot/isolinux/ cp /usr/share/syslinux/vesamenu.c32 CDroot/isolinux/ # Create the ISO. rm -f boot.iso mkisofs -o boot.iso \ -J -r \ -V boot \ -b isolinux/isolinux.bin -c isolinux/boot.cat \ -no-emul-boot -boot-load-size 4 -boot-info-table \ CDroot