Dans l’article précédent « Proxmox VE : Créer un template Alpine Linux avec Cloud-Init », nous avons vu comment créer un template VM réutilisable. Une question revient souvent : comment ajouter des packages ou des configurations personnalisées tout en conservant les paramètres définis dans l’interface Proxmox ?
La réponse se trouve dans l’utilisation de vendor-data plutôt que user-data.
Le problème : cicustom user écrase tout
Beaucoup de tutoriels en ligne suggèrent d’utiliser --cicustom "user=local:snippets/config.yaml" pour ajouter des personnalisations Cloud-Init. Cette approche pose un problème majeur : elle remplace entièrement la configuration utilisateur générée par Proxmox.
Concrètement, si vous définissez :
qm set $VMID --ciuser monuser
qm set $VMID --cipassword $(openssl passwd -6 'monsecret')
qm set $VMID --sshkeys ~/.ssh/id_ed25519.pub
qm set $VMID --cicustom "user=local:snippets/config.yaml"
Les paramètres ciuser, cipassword et sshkeys seront ignorés. Seul le contenu de votre fichier YAML sera appliqué.
La solution : utiliser vendor-data
Proxmox ne génère pas de vendor-data par défaut. L’utilisation de --cicustom "vendor=..." permet donc d’ajouter des configurations personnalisées sans écraser celles de l’interface.
qm set $VMID --cicustom "vendor=local:snippets/vendor-data.yaml"
Cloud-Init fusionne automatiquement les configurations user-data (générée par Proxmox) et vendor-data (votre fichier personnalisé).
Préparer le stockage Snippets
Vérifiez que les snippets sont activés sur votre stockage :
pvesm status
pvesm set local --content images,rootdir,vztmpl,backup,iso,snippets
Les fichiers se placent dans /var/lib/vz/snippets/.
Exemples de configurations par distribution
Alpine Linux (OpenRC)
Alpine utilise OpenRC comme système d’init. Les commandes systemctl des tutoriels classiques ne fonctionnent pas.
Créez le fichier /var/lib/vz/snippets/alpine-vendor.yaml :
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
runcmd:
- rc-update add qemu-guest-agent default
- rc-service qemu-guest-agent start
Version avancée avec SSH post-quantique (Alpine 3.21+ avec OpenSSH 9.9) :
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
write_files:
- path: /etc/ssh/sshd_config.d/kex-algorithms.conf
content: |
KexAlgorithms mlkem768x25519-sha256,curve25519-sha256
permissions: "0644"
owner: root:root
runcmd:
- rc-update add qemu-guest-agent default
- rc-service qemu-guest-agent start
- rc-service sshd restart
Appliquez la configuration :
qm set $VMID --cicustom "vendor=local:snippets/alpine-vendor.yaml"
Debian / Ubuntu (systemd)
Créez le fichier /var/lib/vz/snippets/debian-vendor.yaml :
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
Version avancée avec configuration SSH :
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
write_files:
- path: /etc/ssh/sshd_config.d/99-custom.conf
content: |
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
permissions: "0644"
owner: root:root
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
- systemctl restart sshd
Rocky Linux / AlmaLinux / RHEL (systemd + dnf)
Créez le fichier /var/lib/vz/snippets/rhel-vendor.yaml :
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
Version avancée avec SELinux et Cockpit :
#cloud-config
package_update: true
package_upgrade: true
packages:
- qemu-guest-agent
- cockpit
- policycoreutils-python-utils
write_files:
- path: /etc/ssh/sshd_config.d/99-custom.conf
content: |
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
permissions: "0600"
owner: root:root
runcmd:
- systemctl enable qemu-guest-agent
- systemctl start qemu-guest-agent
- systemctl enable --now cockpit.socket
- firewall-cmd --permanent --add-service=cockpit
- firewall-cmd --reload
- systemctl restart sshd
Script complet de déploiement
Voici un script paramétré pour créer une VM depuis un template avec vendor-data :
#!/bin/bash
set -e
TEMPLATE_ID=9000
VM_ID=200
VM_NAME="vm-test"
STORAGE="local-lvm"
VENDOR_FILE="alpine-vendor.yaml"
CI_USER="admin"
SSH_KEY_FILE="$HOME/.ssh/id_ed25519.pub"
qm clone $TEMPLATE_ID $VM_ID --name $VM_NAME --full
qm set $VM_ID --memory 2048 --cores 2
qm resize $VM_ID scsi0 +8G
qm set $VM_ID --ciuser $CI_USER
qm set $VM_ID --sshkeys $SSH_KEY_FILE
qm set $VM_ID --ipconfig0 ip=dhcp
qm set $VM_ID --cicustom "vendor=local:snippets/$VENDOR_FILE"
qm cloudinit update $VM_ID
qm start $VM_ID
echo "VM $VM_NAME ($VM_ID) démarrée avec succès"
Points clés à retenir
| Paramètre | Comportement |
|---|---|
--cicustom "user=..." | Remplace la config Proxmox (ciuser, cipassword, sshkeys ignorés) |
--cicustom "vendor=..." | S’ajoute à la config Proxmox (paramètres conservés) |
--cicustom "network=..." | Remplace la config réseau Proxmox |
--cicustom "meta=..." | Remplace les métadonnées Proxmox |
Vérification post-déploiement
Après le démarrage de la VM, vérifiez que Cloud-Init a bien appliqué les configurations :
cloud-init status --wait
cat /var/log/cloud-init-output.log
Pour vérifier le QEMU Guest Agent depuis Proxmox :
qm agent $VMID ping
qm agent $VMID network-get-interfaces
Aller plus loin
Cette approche Infrastructure as Code ouvre la voie à des déploiements automatisés plus complexes : installation de Docker ou Podman, configuration de serveurs web (Nginx, Apache), déploiement de bases de données (MariaDB, PostgreSQL), ou intégration avec Ansible pour la configuration post-déploiement.