Cloud-Init - Templates Proxmox

Cloud-Init permet de provisionner automatiquement les VMs créées depuis un template : hostname, utilisateur, clés SSH, packages, scripts de démarrage. Sur Proxmox, les paramètres cloud-init sont injectés via un lecteur ide2 dédié et peuvent être enrichis avec un fichier vendor-data stocké dans les snippets.


Prérequis

Sur le nœud Proxmox où le template sera créé :

apt install libguestfs-tools

Le stockage local doit avoir le type snippets activé dans Datacenter → Storage → local → Content.


Création du template

Étape 1 - Télécharger l’image cloud

cd /var/lib/vz/template/iso/
wget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2

Étape 2 - Pré-installer les packages dans l’image

virt-customize modifie l’image avant le premier démarrage - permet d’éviter de dépendre du réseau pour les packages critiques.

virt-customize -a debian-13-genericcloud-amd64.qcow2 --install sudo,qemu-guest-agent

Étape 3 - Créer la VM

qm create 9999901 \
  --name debian13-cloud \
  --memory 2048 \
  --balloon 0 \
  --cores 1 \
  --sockets 1 \
  --cpu host \
  --machine q35 \
  --numa 1 \
  --net0 virtio,bridge=vmbr0 \
  --hotplug disk,network,memory \
  --onboot 1 \
  --agent 1,fstrim_cloned_disks=1
  • --balloon 0 : désactive le ballooning mémoire (non adapté aux VMs avec charge prévisible)
  • --cpu host : expose les instructions CPU du nœud à la VM (meilleures performances)
  • --machine q35 : chipset moderne, requis pour PCIe, NVMe et certaines fonctions UEFI
  • --numa 1 : active la topologie NUMA (pertinent sur nœuds multi-socket)
  • --agent 1,fstrim_cloned_disks=1 : active le qemu-guest-agent et le fstrim automatique des disques clonés

Étape 4 - Importer le disque

qm importdisk 9999901 debian-13-genericcloud-amd64.qcow2 educeph --format qcow2

Après l’import, le disque apparaît comme unused0 dans la conf. L’attacher avec les options de performance :

qm set 9999901 \
  --scsihw virtio-scsi-single \
  --scsi0 educeph:vm-9999901-disk-0,discard=on,iothread=1,ssd=1
  • virtio-scsi-single : un contrôleur par disque, permet l’iothread dédié
  • discard=on : propage le TRIM/UNMAP au stockage Ceph
  • iothread=1 : thread I/O dédié à ce disque (meilleures performances)
  • ssd=1 : expose le disque comme SSD à l’OS (optimise les comportements d’écriture)

Étape 5 - Configurer le lecteur cloud-init et le boot

# Lecteur cloud-init sur Ceph
qm set 9999901 --ide2 educeph:cloudinit

# Ordre de démarrage
qm set 9999901 --boot order=scsi0

# Console série (requis pour cloud-init sur cloud images)
qm set 9999901 --serial0 socket --vga serial0

# Utilisateur et IP par défaut
qm set 9999901 --ciuser root --ipconfig0 ip=dhcp

Étape 6 - Associer le fichier vendor-data

qm set 9999901 --cicustom "vendor=local:snippets/vendor-data"

Étape 7 - Protéger et convertir en template

# Protection contre la suppression accidentelle
qm set 9999901 --protection 1

# Conversion en template (irréversible)
qm template 9999901

Fichier vendor-data

Le vendor-data est appliqué après le user-data généré par Proxmox (hostname, utilisateur, clé SSH de l’interface). Il permet d’ajouter des customisations sans écraser ce que Proxmox injecte.

Les packages, clé SSH et utilisateur root sont configurés via l’onglet Cloud-Init dans l’interface Proxmox (ils sont injectés dans le user-data généré automatiquement). Le vendor-data se limite à l’exécution du script de post-configuration.

Créer le fichier sur le nœud Proxmox :

nano /var/lib/vz/snippets/vendor-data

Contenu :

#cloud-config

runcmd:
  - /root/script-user-data.sh

vendor-data vs user-data : utiliser vendor= dans --cicustom préserve le user-data généré par Proxmox (hostname, utilisateur, clé SSH de l’interface). Utiliser user= le remplace entièrement.


Script de post-configuration

Le script est embarqué dans l’image lors du virt-customize (voir étape 2). Il configure chrony pour utiliser la passerelle locale (VIP VRRP du segment) comme serveur NTP primaire.

nano /tmp/script-user-data.sh

Contenu :

#!/bin/bash

gateway=$(ip route | awk '/default/ {print $3}')

cat <<EOF > /etc/chrony/sources.d/10-custom.sources
# Local NTP Server
server $gateway iburst prefer

# Fallback NTP Pool
pool fr.pool.ntp.org iburst maxsources 2
EOF

systemctl enable chrony && systemctl restart chrony

Embarquer le script dans l’image avec virt-customize :

virt-customize -a debian-13-genericcloud-amd64.qcow2 \
  --install sudo,qemu-guest-agent \
  --upload /tmp/script-user-data.sh:/root/script-user-data.sh \
  --run-command "chmod +x /root/script-user-data.sh"

Au premier démarrage, cloud-init exécute /root/script-user-data.sh qui détecte automatiquement la passerelle du segment et configure chrony. Chaque VM clonée pointe ainsi vers le FW de son propre segment sans configuration manuelle.

Vérifier ce que Proxmox génère pour une VM donnée :

qm cloudinit dump <vmid> user

Clonage et utilisation

Depuis le template, cloner une nouvelle VM :

qm clone 9999901 <nouveau-vmid> --name <hostname> --full --storage educeph

Au premier démarrage, cloud-init :

  1. Applique le user-data Proxmox (hostname, utilisateur, clé SSH de l’interface GUI)
  2. Applique le vendor-data (packages, runcmd, clé SSH supplémentaire)

Problèmes connus

disk unused après importdisk

Après qm importdisk, le disque n’est pas automatiquement attaché - il reste en unused0 dans la conf. Toujours suivre avec qm set --scsi0 pour l’attacher.

vendor-data non appliqué

Si le fichier vendor-data n’est pas dans /var/lib/vz/snippets/ ou que le stockage local n’a pas Snippets activé dans son Content, cloud-init ignore silencieusement le fichier.


Sources


Retour en haut