Creating a cloud-init config disk for non-cloud boots

There are lots of cloud disk images floating around. They are designed to run in clouds where there is a boot-time network service called cloud-init available that provides initial configuration. If that’s not present, or you’re just trying to boot these images in KVM/libvirt directly without any cloud, then things can go wrong.

Luckily it’s fairly easy to create a config disk (aka “seed disk”) which you attach to the guest and then let cloud-init in the guest get its configuration from there. No cloud, or even network, required.

I’m going to use a tool called virt-make-fs to make the config disk, as it’s easy to use and doesn’t require root. There are other tools around, eg. make-seed-disk which do a similar job. (NB: You might hit this bug in virt-make-fs, which should be fixed in the latest version).

I’m also using a cloud image downloaded from the Fedora project, but any cloud image should work.

First I create my cloud-init metadata. This consists of two files. meta-data contains host and network configuration:

instance-id: iid-123456
local-hostname: cloudy

user-data contains other custom configuration (note #cloud-config is
not a comment, it’s a directive to tell cloud-init the format of the file):

#cloud-config
password: 123456
runcmd:
 - [ useradd, -m, -p, "", rjones ]
 - [ chage, -d, 0, rjones ]

(The idea behind this split is probably not obvious, but apparently it’s because the meta-data is meant to be supplied by the Cloud, and the user-data is meant to be supplied by the Cloud’s customer. In this case, no cloud, so we’re going to supply both!)

I put these two files into a directory, and run virt-make-fs to create the config disk:

$ ls
meta-data  user-data
$ virt-make-fs --type=msdos --label=cidata . /tmp/seed.img
$ virt-filesystems -a /tmp/seed.img --all --long -h
Name      Type        VFS   Label   MBR  Size  Parent
/dev/sda  filesystem  vfat  cidata  -    286K  -
/dev/sda  device      -     -       -    286K  -

Now I need to pass some kernel options when booting the Fedora cloud image, and the only way to do that is if I boot from an external kernel & initrd. This is not as complicated as it sounds, and virt-builder has an option to get the kernel and initrd that I’m going to need:

$ virt-builder --get-kernel Fedora-cloud.raw
download: /boot/vmlinuz-3.9.5-301.fc19.x86_64 -> ./vmlinuz-3.9.5-301.fc19.x86_64
download: /boot/initramfs-3.9.5-301.fc19.x86_64.img -> ./initramfs-3.9.5-301.fc19.x86_64.img

Finally I’m going to boot the guest using KVM (you could also use libvirt with a little extra effort):

$ qemu-kvm -m 1024 \
    -drive file=Fedora-cloud.raw,if=virtio \
    -drive file=seed.img,if=virtio \
    -kernel ./vmlinuz-3.9.5-301.fc19.x86_64 \
    -initrd ./initramfs-3.9.5-301.fc19.x86_64.img \
    -append 'root=/dev/vda1 ro ds=nocloud-net'

You’ll be able to log in either as fedora/123456 or rjones (no password), and you should see that the hostname has been set to cloudy.

5 Comments

Filed under Uncategorized

5 responses to “Creating a cloud-init config disk for non-cloud boots

  1. Pingback: Masking systemd services in a guest | Richard WM Jones

  2. I’ve also done this in a different way in my vagrantify script (used to add an initial vagrant user + repos etc to a distro cloud image), where I used libguestfs to add user-data to /var/lib/cloud/seed/. The downside is that the image is modified, but this means it can then be booted in vagrant-libvirt etc without having to configure the seed disk.

    Code: https://github.com/domcleal/vagrantify

  3. Deepak C Shetty

    Hi Richard, what if i wanted to use the fedora cloud image in my openstack (actually local devstack) setup. Whats the right way to pass the no-cloud-init stuff in nova boot method ?

    • rich

      I don’t know .. Surely there is a cloud init service already in OpenStack so this is not necessary? In any case it’s best to ask on one of the OpenStack mailing lists or fora.

  4. Rocky

    Hi, Richard, i have one question about the cloud-init for non-cloud boot. I generated the seed.img, and via libvirt direct boot options to start the VM. But i have some troubles to make cloud-init to do the user-data commands. Normally, we could see the seed.img as one normal disk , can we see those user-data/meta-data files as well inside the VM? What commands could i use to start the cloud-init, I used “cloud-init init” but looks not correct.
    Thanks a lot

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.