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:
- Go to the VM's Home page.
- Click Advanced.
- 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
- In the Xen Orchestra left-hand menu, go to Settings > Cloud Configs.
- Click + New.
- Name: Give it a descriptive name (e.g., "Rocky-Web-Server").
- Content: Paste your
#cloud-configYAML. - Click Create.
2. Using the Dropdown
When creating a new VM:
- Go to the Install settings section.
- In the Config dropdown, select your saved template.
- 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 0and thensudo cloud-init init --local. If it works, runrestorecon -Rv /etc/cloudin your Golden Image before making the template.
- Test: Run
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: falseis 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
localhostbefore converting.
3. Packages Not Installing
- Network Delay: If the network isn't fully initialized by NetworkManager before cloud-init starts the
dnfmodule, 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.logto see ifdnfwas 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.