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:
And you'll have a brand new nocloud.iso ISO image.
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.
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.