Cloud-init is a program that configures a guest virtual machine when it first boots based on configuration data that's supplied to it via network or a storage volume. It is capable of setting things like the guest's network configuration (IP addresses, routes, resolvers), account credentials and SSH authorized keys.

Building Cloud-Init images[edit | edit source]

Linux images that support Cloud-Init should have the Cloud-Init package installed and enabled on start up.

Distro Commands
RHEL / Rocky Linux / CentOS
## Cloud Init
# yum -y install cloud-init cloud-utils-growpart gdisk
# systemctl enable cloud-init.service
Alpine Linux
## Cloud Init
# apk add cloud-init

## Start Cloud-Init on Boot
# rc-update add cloud-init default
# rc-update add cloud-init-local default
# rc-update add cloud-config default
# rc-update add cloud-final default

Default user[edit | edit source]

The default username for the non-super user account is 'cloud-user'. Some distros use a different default user such as 'alpine' for Alpine Linux or 'ubuntu' for Ubuntu. If you wish to override this username, you need to edit the cloud.cfg configuration file. For my Rocky Linux image, I ran the following to change the default username.

## The default user is 'cloud-user'. we'll change this to 'rocky'.
# sed -i "s/name: cloud-user/name: rocky/" /etc/cloud/cloud.cfg
Do not create the default user account
I noticed that some Packer builds create the default user account as part of the initial image set up. Don't do this. It's intended for the username to be overridden by the initial VM cloud-init configuration. Cloud-Init will take care of the user account creation, SSH authorized key setup, and also setting up the "Please login as the user X rather than the user Y" message on the root account.

The default user has their password locked, thereby requiring authentication using SSH keys. You may change this by modifying cloud.cfg as well:

# sed -i "s/lock_passwd: true/lock_passwd: false/" /etc/cloud/cloud.cfg

Hypervisor support[edit | edit source]

Proxmox[edit | edit source]

Proxmox supports cloud-init using either the NoCloud (v1, used for Linux based guest OSes) or ConfigDrive (v2, used for Windows based guest OSes) data sources. To learn more about different Cloud-Init data sources, see https://cloudinit.readthedocs.io/en/latest/topics/datasources.html#known-sources.

A NoCloud configuration data is passed to the guest using a 4MB CD-ROM image. If you are creating a new VM, you must attach this CD-ROM device under 'Hardware' -> 'Add' -> 'CloudInit Drive'. Any changes made to the Cloud-Init settings will require this CD-ROM image to be regenerated.

When building images for use with Proxmox, it's recommended to add the following cloud.cfg.d file to restrict the data sources to only the supported options. Otherwise, you may have the VM try downloading the configs using some other method until it times out.

# /etc/cloud/cloud.cfg.d/99_pve.cfg
datasource_list: [ NoCloud, ConfigDrive ]


Troubleshooting[edit | edit source]

Cloud-Init isn't setting the static IP address[edit | edit source]

On Alpine Linux, Cloud-Init runs but the VM is still obtaining the IP address via DHCP.

After much debugging, I believe the issue comes down to the networking service starting before cloud-init. As a result, the network configs in /etc/network/interfaces isn't being written to by Cloud-Init in time and the networking service uses DHCP. The fix here is to make networking start after cloud-init. To do this, remove the networking service from the boot runlevel and re-add it to the default runlevel. Because 'networking' comes after 'cloud-init', cloud-init should run before networking.

As part of my packer provisioning script, I added the following lines:

## Start ntworking after cloudinit?
# rc-update del networking boot     
# rc-update add networking default