Aral Balkan

Mastodon icon RSS feed icon

Rerun cloud-init on multipass

Today, I had the need to experiment with rerunning cloud-init on a virtual machine created with multipass. You can use cloud-init with multipass by specifying a cloud-init.yaml file when creating your instance. e.g,

multipass launch --name my-instance --cloud-init ./cloud-init.yaml

This is all well and good and works as you would expect.

However, today, I wanted to experiment with running cloud-init on an already-provisioned instance. My use case is that the lovely folks at (a project by Greenhost and the Open Technology Fund) who have given a generous amount of free hosting do not yet support cloud-init when provisioning a server. So I wanted to see if I can run my cloud-init script after I provisioned a server and I wanted to test that out locally using multipass.

How to rerun cloud-init

Ordinarily, it is actually quite simply to rerun cloud-init after a server has been provisioned.

First, you use the clean command to remove the current build artifacts:

sudo cloud-init clean

Then, you specify your meta-data and user-data files in the /var/lib/cloud/nocloud-net/ directory, which you must create:

sudo mkdir /var/lib/cloud/nocloud-net/
sudo touch /var/lib/cloud/nocloud-net/meta-data
sudo nano /var/lib/cloud/nocloud-net/user-data

Then, paste your cloud-config file into the editor and save (in nano, Ctrl-o + Ctrl-x).

Finally, run the init command to re-initialise your instance using cloud-init:

sudo cloud-init init

Now, in theory, this should work.

In practice, however, we end up with a /var/lib/cloud/instance/user-data.txt file that only contains the vendor-data provided by multipass, not our user-data.


Say you have created a multipass instance without specifying a cloud-init.yaml file, like this:

multipass launch --name my-instance

To run your cloud-config file, you first have to SSH into the box. You can either do this by running multipass ls and finding the IP address and then using the account and key that multipass automatically creates to ssh to it (e.g., ssh multipass@<ENTER THE IP-ADDRESS OF YOUR INSTANCE HERE> -i $(locate multipass | grep .*id_rsa)) or you can use the handy shortcut that multipass provides:

multipass shell <NAME OF YOUR INSTANCE>

Then, to find the culprit, run the status command in verbose mode:

sudo cloud-init status --long

Which should give you something along the lines of:

status: running
time: Sat, 15 Jun 2019 21:11:55 +0000
DataSourceNoCloudNet [seed=/var/lib/cloud/seed/nocloud-net,/dev/sr0][dsmode=net]

The first seed source you see is the one you defined. The second one is the one that multipass passes in. You can cat it to see what it has:

sudo cat /dev/sr0

You should see the vendor-data specified and, at the end of that, you should see an empty cloud-init section:


This is also what I saw at the end of /var/lib/cloud/instance/user-data.txt and that led to me to think that perhaps our datasource was being ignored or overwritten.

You can find the data sources defined in the file _/etc/cloud/cloud.cfg.d/90dpkg.cfg. To see its contents:

cat /etc/cloud/cloud.cfg.d/90_dpkg.cfg

And you should find a long list similar to:

datasource_list: [ NoCloud, ConfigDrive, OpenNebula, DigitalOcean, Azure, AltCloud, OVF, MAAS, GCE, OpenStack, CloudSigma, SmartOS, Bigstep, Scaleway, AliYun, Ec2, CloudStack, Hetzner, IBMCloud, None ]

I had a suspicion that the ConfigDrive data source might have been overriding my user-data, so I edited that file and reduced the list down to:

datasource_list: [ NoCloud, None ]

Then, after running sudo cloud-init clean and sudo cloud-init init again, I had multipass successfully using my cloud-config from /var/lib/cloud/nocloud-net/user-data.

Information about cloud-init seems hard to come by so while I’m mostly documenting this for my own sake, I hope it also ends up helping someone else out in the future.

Useful resources

From Cloud-init docs

Cloud-init docs