cloud-init
cloud-init is a tool to customize a VM during the first boot.
Why cloud-init?
I can install and update software, create users, set up public ssh key, run commands, etc. Combined with Terraform, I can provision a new VM in 1 command.
Ubuntu cloud image
Ubuntu 24.04 cloud image is the base image for my VMs. It's pre-installed and updated with the latest packages, so it saves me a lot of time from downloading and installing updates manually.
Examples
Basic example
#cloud-config
users:
- default
# create a sudo user
- name: ${username}
  groups:
  - sudo
  shell: /bin/bash
  # allow ssh login for this user
  ssh_authorized_keys:
  %{~ for key in ssh_public_keys ~}
    - ${key}
  %{~ endfor ~}
  # allow sudo without password
  sudo: ALL=(ALL) NOPASSWD:ALL
# update and upgrade packages
package_update: true
package_upgrade: true
# install packages
packages:
  - qemu-guest-agent # need this for guest mode in Proxmox
  - curl
  - ca-certificates
  - unattended-upgrades
# run  commands after cloud-init finishes
runcmd:
  - timedatectl set-timezone America/New_York
  - systemctl enable qemu-guest-agent
  - systemctl start qemu-guest-agent
  - echo "done" > /tmp/cloud-config.done
NFS server example
# the rest of the config is the same as above
# create a new file and write nfs mounts
write_files:
- path: /etc/exports
  content: |
    /shares           192.168.0.0/16(rw,fsid=0,no_subtree_check,sync,all_squash,anonuid=1001,anongid=1001)
    /shares/configs   192.168.0.0/16(rw,no_subtree_check,sync,all_squash,anonuid=1001,anongid=1001)
packages:
  - nfs-kernel-server
  # ...
runcmd:
  - mkdir -p /shares/configs
  - chmod 775 -R /shares
  - systemctl start nfs-kernel-server.service
  - exportfs -ar
  # ...
Validation
cloud-init config can be validated with:
cloud-init schema --config-file a.yaml
After the VM is created, its status can be checked with:
cloud-init status
Troubleshooting
In case of issues, the logs can be found in
/var/log/cloud-init.log and /var/log/cloud-init-output.log.