Booting cloud images with libvirt
Most major distributions now provide “cloud-enabled” images designed for use in cloud environments like OpenStack and AWS. These images are usually differentiated by (a) being relatively small, and (b) running cloud-init at boot to perform initial system configuration tasks using metadata provided by the cloud environment.
Because of their small size and support for automatic configuration (including such useful tasks as provisioning ssh keys), these images are attractive for use outside of a cloud environment. Unfortunately, when people first try to boot them they are met with frustration as first the image takes forever to boot as it tries to contact a non-existent metadata service, and then when it finally does boot they are unable to log in because the images typically only support key-based login.
Fortunately, there are ways to work around these issues. In addition to working with various network-accessible metadata services, cloud-init is also able to read configuration information from an attached [virtual] CD-ROM device. This is known as a “configuration drive”, and it is relatively easy to create.
For this purpose, the simplest solution is use cloud-init’s “no
cloud” data source. For this, we need to create an ISO filesystem
creating two files, meta-data
and (optionally) user-data
.
The meta-data file⌗
The meta-data
file is effectively a YAML version of the data
typically available in the EC2 metadata service, and will look
something like this:
instance-id: my-instance-id
local-hostname: my-host-name
The instance-id
key is required. You can also include SSH public
keys in this file, like this:
instance-id: my-instance-id
local-hostname: my-host-name
public-keys:
- ssh-rsa AAAAB3NzaC1...
You will see examples that place ssh keys in the user-data
file
instead, but I believe this is the wrong solution, since it forces you
to use a “cloud-config” format user-data
file. Putting ssh keys
into the meta-data
provides you more flexibility with your
user-data
content.
The user-data file⌗
The user-data
can be any of the various formats supported by
cloud-init. For example, it could simply be a shell script:
#!/bin/sh
yum -y install some-critical-package
Or it could be a cloud-config YAML document:
#cloud-config
write-files:
- path: /etc/profile.d/gitaliases.sh
content: |
alias gc="git commit"
alias gcv="git commit --no-verify"
runcmd:
- setenforce 1
Putting it all together⌗
Once you have created your meta-data
and user-data
files, you can
create the configuration drive like this:
genisoimage -o config.iso -V cidata -r -J meta-data user-data
To boot an instance using this configuration drive, you could do something like this:
virt-install -n example -r 512 -w network=default \
--disk vol=default/fedora-21-cloud.qcow2 --import \
--disk path=config.iso,device=cdrom
(This assumes, obviously, that you have an image named
fedora-21-cloud.qcow2
available in libvirt’s default
storage
pool.)
A little automation⌗
I have written a create-config-drive script that will automate this process. With this script available, the above process is simply:
create-config-drive -k ~/.ssh/id_rsa.pub -u user-data config.iso
adding pubkey from /home/lars/.ssh/id_rsa.pub
adding user data from userdata
generating configuration image at config.iso