Cloud-Init & Golden Images (Rocky Linux 10)

Automate your VM deployments using Cloud-Init and templates. This guide focuses on Rocky Linux 10 (Red Quartz), a popular RHEL-based choice for stable home lab infrastructure.

What is Cloud-Init?

Cloud-Init is a multi-distribution package that handles early initialization of a cloud instance. It allows you to inject SSH keys, set hostnames, and install packages automatically upon the first boot.

Creating a "Golden Image"

1. Create a Base VM

Install a fresh instance of Rocky Linux 10. During installation, select a "Minimal" software selection to keep the image small.

Note: Rocky Linux 10 requires x86-64-v3 CPU architecture. Ensure your host supports this (Haswell or newer).

2. Install Guest Tools & Cloud-Init

# Update the system
sudo dnf update -y

# Install Cloud-Init
sudo dnf install cloud-init -y

# Install XCP-ng Guest Tools (Manual ISO method)
# 1. Insert the Guest Tools ISO in Xen Orchestra
sudo mount /dev/cdrom /mnt
sudo /mnt/Linux/install.sh

3. Configure Cloud-Init for Xen

Ensure the NoCloud datasource is prioritized:

# Create datasource configuration
sudo tee /etc/cloud/cloud.cfg.d/99_xcp.cfg <<EOF
datasource_list: [ NoCloud, ConfigDrive, None ]
EOF

# Enable services
sudo systemctl enable --now cloud-init-local.service cloud-init.service cloud-config.service cloud-final.service

4. Optional: Disable IPv6

If your home lab environment does not use IPv6, it is recommended to disable it in the Golden Image to avoid delay and routing issues.

# Disable at the kernel level
sudo tee /etc/sysctl.d/70-disable-ipv6.conf <<EOF
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
EOF
sudo sysctl --system

# Disable in NetworkManager (replace eth0 with your interface name)
sudo nmcli connection modify eth0 ipv6.method "disabled"
sudo nmcli connection up eth0

5. Clean up the VM

Before converting it into a template, remove any machine-specific identifiers:

# Clean cloud-init state
sudo cloud-init clean --logs

# Clear command history
history -c

# Shutdown the VM
sudo poweroff

5. Convert to Template

In the Xen Orchestra UI:

  1. Go to the VM's Home page.
  2. Click Advanced.
  3. Click Convert to Template.

Managing Reusable Cloud-Configs

Instead of pasting YAML every time, you can store your configurations in Xen Orchestra to be selected from a dropdown list.

1. Store your Configs

  1. In the Xen Orchestra left-hand menu, go to Settings > Cloud Configs.
  2. Click + New.
  3. Name: Give it a descriptive name (e.g., "Rocky-Web-Server").
  4. Content: Paste your #cloud-config YAML.
  5. Click Create.

2. Using the Dropdown

When creating a new VM:

  1. Go to the Install settings section.
  2. In the Config dropdown, select your saved template.
  3. The text area will automatically populate with your YAML.

Deploying from Template

When you create a new VM from this template, use the Cloud-config section in the New > VM screen.

Important: Do NOT use curly braces { } in your hostname as it will break the YAML parser.

#cloud-config
hostname: rocky-server-01
fqdn: rocky-server-01.lan
manage_etc_hosts: true
preserve_hostname: false

users:
  - name: rockyuser
    groups: wheel
    sudo: ALL=(ALL) NOPASSWD:ALL
    ssh_authorized_keys:
      - ssh-rsa AAAAB3Nza...
package_update: true
packages:
  - cockpit
  - git
  - vim

Troubleshooting

1. init-local Stage Failures

If the cloud-init-output.log shows a "failed run of stage init-local," it means cloud-init could not find its configuration source before starting.

  • Xen Orchestra "Config Drive": Ensure that when deploying the VM from the template, you have the "Config Drive" (or "Cloud-init") option enabled in the "New VM" screen. Without this, the virtual ISO containing your YAML never gets attached.
  • Datasource Typo: Double-check your /etc/cloud/cloud.cfg.d/99_xcp.cfg. It must be exact: datasource_list: [ NoCloud, ConfigDrive, None ]. A single missing bracket or extra space can cause a crash.
  • SELinux Blocking Mount: Rocky 10's SELinux can sometimes prevent cloud-init from mounting the virtual CD-ROM.
    • Test: Run sudo setenforce 0 and then sudo cloud-init init --local. If it works, run restorecon -Rv /etc/cloud in your Golden Image before making the template.

2. Hostname is not changing

Rocky Linux is protective of the system identity. If the hostname stays as the template's name:

  • Preserve Hostname: Ensure preserve_hostname: false is in your config.
  • YAML Syntax: Check your logs for Unexpected failure parsing userdata. If you used {rocky-cloud}, the braces caused a syntax error that made cloud-init skip the hostname stage.
  • Template Cleanliness: Ensure your Golden Image had the hostname set to localhost before converting.

3. Packages Not Installing

  • Network Delay: If the network isn't fully initialized by NetworkManager before cloud-init starts the dnf module, it will fail. Ensure your template has the network set to start automatically.
  • Check logs: Run grep -E "fail|error" /var/log/cloud-init-output.log to see if dnf was blocked by a lock or couldn't reach the mirrors.

4. Debugging Commands

  • cloud-init status --wait: Check the current status.
  • sudo cloud-init query userdata: See if the VM actually received your configuration.
  • journalctl -u cloud-init: View the full initialization log.