Index ¦ Archives ¦ Atom

Testing cloud-init with Vagrant

cloud-init is a standard tool in most cloud computing environments as it's an easy way to provide configuration for provisioning server instances. You provide a YAML config file and it'll use the data to configure the server as needed.

Testing cloud-init in a public can be a bit problematic and time consuming, having to relaunch servers to test the config from a pristine state. It's possible to reset the cloud-init config on the server - but if you want to test that your config file works as expected, it's best to test from a freshly booted server.

Thanks to the Ubuntu Vagrant boxes which are built with cloud-init support, we can test our cloud-init configuration with Vagrant easily. We'll be using the Ubuntu 16.04 Xenial Xerus box to test with - as it's the latest Ubuntu LTS release.

Creating a cloud-init ISO

cloud-init can support multiple data sources for configuration, one of them being an CD image. We'll be using this as an easy way to provide our config files. To generate this we can use genisoimage/mkisofs.

To install on Debian/Ubuntu:

$ sudo apt-get install genisoimage

To install on OS X Macports:

$ sudo port install cdrtools

Next up we'll need our user-data file, the main cloud-init config file:

#cloud-config
chpasswd:
  list: |
    ubuntu:RANDOM
  expire: False

manage_etc_hosts: localhost

ssh_authorized_keys:
  - ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key

This can be customised with the configuration you need to test, however in this example we're adding the default Vagrant insecure public SSH key. Don't worry - Vagrant will replace it shortly after rebooting.

Now we need a meta-data file:

instance-id: iid-0123456789abcdef
local-hostname: ubuntu-xenial

This is just the bare minimum - cloud providers usually provide more data. If you depend on other data provided as metadata then just add it as needed.

To create the ISO image we'll create a Makefile:

nocloud.iso: meta-data user-data
    mkisofs \
        -joliet -rock \
        -volid "cidata" \
        -output nocloud.iso meta-data user-data

Don't forget - a Makefile must be indented with tabs and not spaces!

Now to create the ISO file, all we have to do is run:

$ make

And you'll have a brand new nocloud.iso ISO image.

cloud-init Vagrantfile

Now we can create a Vagrantfile to test our newly generated ISO image:

$ vagrant init ubuntu/xenial64

This will create a sample Vagrantfile, which we'll need to edit:

# -*- mode: ruby -*-
# vi: set ft=ruby :


CLOUD_CONFIG_PATH = File.join(File.dirname(__FILE__), "nocloud.iso")


Vagrant.require_version ">= 1.8.0"

Vagrant.configure(2) do |config|
    config.vm.box = "ubuntu/xenial64"

    # Disable SSH password for 16.04 - we'll add the insecure Vagrant key
    # (don't worry, it's just an example and gets replaced anyway)
    config.ssh.password = nil

    # Disable shared folders
    config.vm.synced_folder ".", "/vagrant", disabled: true

    # Tweak virtualbox
    config.vm.provider :virtualbox do |vb|
        # Attach nocloud.iso to the virtual machine
        vb.customize [
            "storageattach", :id,
            "--storagectl", "SCSI",
            "--port", "1",
            "--type", "dvddrive",
            "--medium", CLOUD_CONFIG_PATH
        ]

        # Speed up machine startup by using linked clones
        vb.linked_clone = true
    end
end

This creates a new virtual machine based on the xenial64 Vagrant box, but replaces the CD/DVD port with our nocloud.iso file.

All you have to do at this point is:

$ vagrant up

Vagrant will start up a virtual machine, customised with your cloud-init config file. If anything goes wrong you can easily vagrant destroy the machine and try again - without the cost of starting a new server in a public cloud.

Using your own SSH keys

If you're developing a user-data file and want to use your own SSH keys instead of Vagrant replacing it on every boot, edit the Vagrantfile and add these lines:

config.ssh.private_key_path = File.expand_path("~/.ssh/id_rsa")
config.ssh.insert_key = false

Don't forget to edit the user-data file and add your own public key to ssh_authorized_keys, and run make to generate a new ISO image.

Conclusion

Testing cloud-init with Vagrant is quick and easy once you've got everything setup.

Source code for this is available in the cloud-init-vagrant repo on GitHub.

© Alex Tomkins.