Do you ever get frustrated with waiting for a heavy VM image to download or with installing operating systems onto virtual machines manually? It can start to feel cumbersome after a while, especially if you bring up and tear down lots of virtual machines as part of your workflow. It’d be nice if spawning a ready-to-use VM was as quick and as easy as it is when using a public cloud.
Good news! It can be. Many Linux distributions (and BSDs) publish what are known as “cloud images” for use in virtual machines. These images are purposefully tiny and contain the bare minimum for what is required to provision a virtual machine.
Create a directory structure for your VMs
This is up to you, however, here’s mine (I like to keep it simple):
$ mkdir -p $HOME/VM/images/base
Download a cloud base image
I’ll use a Fedora Cloud Base Image for the virtual machines, but like the previous step, you can find your own cloud image from your favorite OS distribution. Distributions typically do a good job of explicitly pointing out which download is a cloud image, so I don’t think you’ll have much trouble finding one.
$ curl -Lk https://download.fedoraproject.org/pub/fedora/linux/releases/33/Cloud/x86_64/images/Fedora-Cloud-Base-33-1.2.x86_64.qcow2 > $HOME/VM/images/base/fedora_cloud_base_33.qcow2
The important thing here is that the cloud image is a qcow2 image. If it’s a raw image, you’ll have to convert it like so:
$ qemu-img convert -f raw -O qcow2 path_to_raw_image.raw new_filename_for_qcow2_image.qcow2
Create a new image from the cloud base image
I usually make a new folder where I can put artifacts related to my individual VMs as needed:
$ mkdir $HOME/VM/fedora_33 $ qemu-img create -f qcow2 -b $HOME/VM/images/base/fedora_cloud_base_33.qcow2 $HOME/VM/fedora_33/hdd.qcow2 8G
Deriving a new image from the base image is a neat trick because it allows us to create new VM images from the base image without having to download a new image again.
Create a cloud-init bootstrap image
The cloud image that we’re using requires
cloud-init to perform some first-time setup. I’m trying to use only the bare minimum configuration to bring up a virtual machine here, but curious readers should head over to
cloud-init’s documentation if they’d like to learn other ways that it can be used to customize their virtual machine.
$ cd $HOME/VM/fedora_33 $ touch meta-data $ cat > user-data << EOF #cloud-config system_info: default_user: name: fedora chpasswd: list: | fedora:password expire: False resize_rootfs: True ssh_authorized_keys: - ssh-rsa AAAAB3Nza... EOF $ genisoimage -output seedci.iso -volid cidata -joliet -rock user-data meta-data
Launch your virtual machine
Here is a super minimal QEMU command line for launching your new VM! You’ll want to supplement this with more arguments to fit your needs (i.e.,
$ qemu-system-x86_64 -m 512 -drive file=hdd.qcow2 -cdrom seedci.iso
Log in with the user account that was described in the
user-data file. In the case of this article, the username is
fedora and the password is
password. Obviously this configuration is mainly for cheap, disposable VMs that will be used for local development/testing. This configuration is unsuitable for a production environment.
You can remove the
-cdrom argument from the command line for subsequent launches because cloud-init will only use it for the instance’s first boot to configure things.