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
.
Pingback: Masking systemd services in a guest | Richard WM Jones
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
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 ?
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.
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