Pendant longtemps, mes VM Proxmox étaient montées à la main. Je cliquais dans un installeur, j'ajoutais mon utilisateur, je collais une clé SSH, j'installais le guest agent, puis j'oubliais la moitié de ce que j'avais fait pour la VM suivante. Elles fonctionnaient. Elles n'étaient simplement pas reproductibles, et je ne saurais pas dire ce qui différait entre deux machines montées à un mois d'intervalle.
Un template cloud-init règle l'essentiel du problème. Cet article explique comment j'en construis un à partir d'une image cloud officielle, en utilisant la CLI qm pour que chaque étape puisse vivre dans un script dans Git. Je n'utilise pas cette configuration depuis longtemps, alors considérez-la comme une méthode qui fonctionne. Je signalerai les points dont je ne suis pas sûr.
Si vous n'avez pas encore d'hôte Proxmox pour essayer, le lab Install Proxmox VE couvre l'installation de base.
Vous vous exercerez à installer Proxmox VE sur deux SSD en miroir avec ZFS et à donner une adresse fixe à l'hôte.
Pourquoi une image cloud plutôt qu'une VM clonée
L'alternative courante consiste à installer une VM à la main, à la nettoyer, puis à la convertir en template. Ça marche, mais le template garde tout l'état que vous y avez laissé : clés d'hôte, machine ID, historique du shell, un paquet oublié. Nettoyer tout ça est une checklist à part entière, et je préfère ne pas avoir à la maintenir.
Une image cloud officielle part d'une base propre. Elle attend que cloud-init la configure au premier démarrage : utilisateur, clés SSH, réseau, hostname. Proxmox peut fournir ces valeurs via un lecteur cloud-init virtuel. Le template reste générique, et chaque clone reçoit son identité au moment de sa création.
Le compromis, c'est qu'on renonce à l'installeur graphique et qu'il faut savoir dès le départ ce que l'on veut. Pour moi, c'est un avantage. La liste de ce que je veux est exactement la documentation que je repousse depuis toujours.
Construire le template
J'utilise ici l'image cloud d'Ubuntu. N'importe quelle distribution qui fournit une image cloud fonctionne de la même façon. Lancez ces commandes sur le nœud Proxmox. L'ID de VM, le nom du stockage et le bridge sont les miens, remplacez-les par les vôtres.
cd /var/lib/vz/template/iso
wget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img
qm create 9000 --name ubuntu-2404-ci \
--memory 2048 --cores 2 \
--net0 virtio,bridge=vmbr0 \
--ostype l26 --agent enabled=1
qm importdisk 9000 noble-server-cloudimg-amd64.img local-zfs
qm set 9000 --scsihw virtio-scsi-pci --scsi0 local-zfs:vm-9000-disk-0
qm set 9000 --ide2 local-zfs:cloudinit
qm set 9000 --boot order=scsi0
qm set 9000 --serial0 socket --vga serial0
Quelques notes sur la raison d'être de chaque élément :
importdisktransforme l'image téléchargée en disque de VM sur votre stockage. Les versions récentes de Proxmox proposent aussiqm disk import. Vérifiez ce que prend en charge votre version.- Le lecteur
cloudinitsuride2est l'endroit où Proxmox écrit les paramètres d'utilisateur, de clé et de réseau que cloud-init lit au démarrage. - La console série est là parce que beaucoup d'images cloud en attendent une. Sans elle, j'ai déjà vu la console web n'afficher rien d'utile. Je ne suis pas certain qu'elle soit indispensable sur toutes les images.
Ne la convertissez pas tout de suite. Occupons-nous d'abord du guest agent.
Le problème du guest agent
L'image cloud n'est pas livrée avec qemu-guest-agent. Sans lui, Proxmox ne peut pas voir l'adresse IP de la VM, et les arrêts propres ainsi que le quiescing pour les sauvegardes sont moins fiables. Je pourrais l'installer à la main et convertir le résultat, mais ça ramènerait le problème du template monté à la main.
J'utilise donc un snippet vendor-data que cloud-init applique au premier démarrage :
#cloud-config
package_update: true
packages:
- qemu-guest-agent
runcmd:
- systemctl enable --now qemu-guest-agent
Enregistrez-le sous /var/lib/vz/snippets/vendor.yaml. Les snippets nécessitent un stockage de type répertoire avec le type de contenu Snippets activé. Le stockage local par défaut peut le faire, mais un stockage sur ZFS comme local-zfs ne peut pas contenir de snippets. Ensuite, attachez-le :
qm set 9000 --cicustom "vendor=local:snippets/vendor.yaml"
qm template 9000
Une réserve pour les clusters : ce fichier de snippet se trouve sur le stockage local d'un seul nœud. Si un clone atterrit sur un nœud qui ne l'a pas, il ne démarrera pas. Je n'ai pas encore décidé comment gérer ça. Les options que je vois sont de copier le fichier sur chaque nœud depuis le même script, ou de placer les snippets sur un stockage partagé. La copie est plus simple, donc je penche de ce côté.
Cloner avec des paramètres
Le template contient ce qui est commun. Chaque clone ajoute ce qui lui est propre :
qm clone 9000 120 --name devvm --full
qm set 120 --ciuser priya --sshkeys ~/.ssh/lab_keys.pub
qm set 120 --ipconfig0 ip=dhcp
qm resize 120 scsi0 32G
qm start 120
L'option --sshkeys prend un fichier de clés publiques. Seules les clés publiques arrivent sur la VM. Je ne définis aucun mot de passe, donc il n'y a rien à faire fuiter ni à renouveler. Si vous voulez une adresse statique, --ipconfig0 ip=10.0.20.50/24,gw=10.0.20.1 s'en charge. Je préfère une réservation DHCP, car cela garde l'adressage à un seul endroit.
Après une minute ou deux, qm guest cmd 120 network-get-interfaces devrait renvoyer des données une fois l'agent démarré. Si la commande expire, c'est probablement que l'agent ne tourne pas encore, ou que le snippet vendor ne s'est pas appliqué.
Ce que je vérifie avant de lui faire confiance
Un template qui démarre n'est pas forcément un template correct. Voici ma courte vérification après chaque reconstruction :
- Me connecter en SSH avec la clé, et confirmer que l'authentification par mot de passe est désactivée.
- Confirmer que le hostname correspond au nom de la VM, et non à celui du template.
- Vérifier
cloud-init status --longpour repérer d'éventuelles erreurs. - Confirmer que le guest agent tourne et que Proxmox affiche l'IP.
- M'assurer que deux clones ne partagent pas le même machine ID :
cat /etc/machine-idsur les deux.
Le dernier point est la raison pour laquelle j'ai choisi une image cloud. C'est aussi celui que j'aimerais le moins découvrir à mes dépens.
Le mettre dans Git
L'objectif est que rien de tout ça ne reste dans ma tête. Les commandes de construction vont dans un seul script shell, le snippet vendor se trouve à côté, et les deux sont commités. Reconstruire le template revient alors à : supprimer la VM 9000, lancer le script. Je n'ai pas encore branché ça sur Ansible. C'est la prochaine étape, et je m'attends à ce que ce soit plus pénible que la version shell, car les modules Proxmox demandent des identifiants d'API à gérer. J'aimerais savoir si ça vaut le coup pour un workflow où l'on travaille sur un seul nœud à la fois.
Ce dont je ne suis pas sûr
- Les mises à jour d'image. L'image
currentest remplacée en amont. Je veux la figer, ou au moins noter une somme de contrôle, pour qu'une reconstruction produise réellement le même résultat. Je n'ai pas encore décidé comment. - La dérive des templates. Les clones ne se mettent pas à jour quand le template change. Je traite les VM comme jetables, avec les données sur un stockage séparé, donc reconstruire coûte moins cher que de patcher une lignée de templates. Je ne suis pas sûr que ça tienne pour toutes les VM que je fais tourner.
- Le comportement en cluster. Je n'ai testé ça que sur un nœud à la fois.
Et vous, comment gérez-vous ça ? Construisez-vous vos templates avec la CLI qm, Terraform, Packer ou autre chose ? Et avez-vous figé vos images de base, ou les laissez-vous évoluer en gérant les surprises ?
Have a question about this guide?
Create a free account to ask the community and join the discussion. Members who run the real thing answer every day.
