
Vous avez créé une première VM Terraform. Mais les paramètres exacts du
bloc libvirt_domain — os.type_machine, devices.disks, virtio,
q35 — sont restés un peu obscurs. Que se passe-t-il si vous oubliez
le champ type_machine ? Pourquoi utiliser virtio et pas ide ?
Ce guide démonte chaque composant d’une VM libvirt déclarée en Terraform, vous montre comment vérifier la VM créée depuis la CLI libvirt, et vous prépare à personnaliser vos VMs pour des scénarios réels.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Anatomie complète du bloc
libvirt_volume: pool, format, image source - Anatomie complète du bloc
libvirt_domain: type, OS, CPU, RAM, disque, réseau - Vérifier depuis virsh :
virsh list,virsh dominfo,virsh dumpxml - Comprendre
virtioet pourquoi ce bus est recommandé - cloud-init : configurer la VM au premier démarrage sans SSH manuel
Prérequis
Section intitulée « Prérequis »- Première infrastructure créée (guide précédent)
- Provider libvirt fonctionnel (terraform init réussi)
Les deux ressources d’une VM KVM
Section intitulée « Les deux ressources d’une VM KVM »Analogie : créer une VM avec libvirt, c’est comme assembler un ordinateur.
Le libvirt_volume est le disque dur — il stocke l’OS. Le libvirt_domain,
c’est le boîtier qui connecte tout : processeur, RAM, disque, carte réseau.
On crée d’abord le disque, puis on assemble la machine.
libvirt_volume → le disque dur (fichier qcow2)libvirt_domain → la VM complète (CPU, RAM, disques, interfaces)Anatomie du bloc libvirt_volume
Section intitulée « Anatomie du bloc libvirt_volume »resource "libvirt_volume" "disk" { name = "lab-vm.qcow2" # (1) Nom du fichier dans le pool libvirt pool = "default" # (2) Pool de stockage cible
target = { format = { type = "qcow2" # (3) Format disque : qcow2 (copy-on-write, recommandé) } }
create = { content = { url = pathexpand("~/images/ubuntu-24.04-cloudimg.img") # (4) Image source } }}| Champ | Rôle | Valeurs courantes |
|---|---|---|
name | Nom du fichier dans le pool | vm-name.qcow2 |
pool | Pool libvirt stockant le volume | default |
format.type | Format disque | qcow2 (recommandé), raw |
create.content.url | Image source (chemin local ou URL) | Chemin absolu local |
Après l’apply, vérifiez le volume :
virsh vol-list default Name Path-------------------------------------------------------- lab-vm.qcow2 /var/lib/libvirt/images/lab-vm.qcow2Anatomie du bloc libvirt_domain
Section intitulée « Anatomie du bloc libvirt_domain »resource "libvirt_domain" "vm" { name = "lab-vm" # (1) Nom affiché dans virsh list type = "kvm" # (2) Hyperviseur : kvm (virtualisation matérielle) memory = 512 # (3) RAM allouée memory_unit = "MiB" # (4) Unité : MiB (toujours expliciter) vcpu = 1 # (5) Nombre de CPUs virtuels
os = { type = "hvm" # (6) Hardware Virtual Machine (mode KVM complet) type_arch = "x86_64" # (7) Architecture du guest type_machine = "q35" # (8) Chipset virtuel : q35 (moderne, PCIe) }
devices = { disks = [ { source = { file = { file = libvirt_volume.disk.path # (9) Chemin du volume créé } } target = { dev = "vda" # (10) Nom du device dans le guest (/dev/vda) bus = "virtio" # (11) Bus virtio (performances maximales) } } ] interfaces = [ { model = { type = "virtio" } # (12) Carte réseau virtio source = { network = { network = "default" } } # (13) Réseau libvirt } ] }}Les champs clés expliqués
Section intitulée « Les champs clés expliqués »type = "kvm" — Utilise la virtualisation matérielle (KVM). L’alternative
qemu utilise l’émulation pure, beaucoup plus lente. Toujours préférer kvm
si le CPU le supporte.
os.type_machine = "q35" — Le chipset virtuel q35 est le standard moderne
pour les guests KVM. Il émule un chipset Intel Q35 avec support PCIe. L’ancien
chipset pc (i440FX) est encore fonctionnel mais moins capable.
target.bus = "virtio" — Le bus virtio est para-virtuel : le guest
sait qu’il tourne dans une VM et utilise des pilotes optimisés. Résultat :
performances disque et réseau bien supérieures à ide ou sata.
Vérifier une VM créée
Section intitulée « Vérifier une VM créée »Après terraform apply, vous disposez de plusieurs commandes virsh pour inspecter :
# Lister toutes les VMsvirsh list --all
# Informations détailléesvirsh dominfo lab-vm
# Voir la configuration XML complètevirsh dumpxml lab-vm | head -40
# Voir les interfaces réseauvirsh domiflist lab-vmRésultat de virsh dominfo :
Id: 1Name: lab-vmUUID: a1b2c3d4-...OS Type: hvmState: runningCPU(s): 1Max memory: 524288 KiBUsed memory: 524288 KiBAjouter cloud-init
Section intitulée « Ajouter cloud-init »Une VM créée sans cloud-init démarre mais n’est pas accessible par SSH : aucun utilisateur défini, aucune clé autorisée. cloud-init configure la VM au premier démarrage depuis un fichier de données.
Analogie : cloud-init est comme une clé USB de configuration que vous branchez à la VM au premier démarrage. Elle lit les instructions (créer un utilisateur, injecter une clé SSH) et les applique automatiquement.
La configuration cloud-init passe par un volume de type cdrom (disque ISO) :
# Données cloud-init : utilisateur et clé SSHresource "libvirt_cloudinit_disk" "init" { name = "lab-vm-init.iso" # Nom du fichier ISO dans le pool pool = "default" user_data = <<-EOF #cloud-config users: - name: ubuntu groups: sudo shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys: - ${trimspace(file(pathexpand("~/.ssh/id_ed25519.pub")))} package_update: true EOF}
resource "libvirt_domain" "vm" { # ... (paramètres précédents)
cloudinit = libvirt_cloudinit_disk.init.id # Attacher le disque cloud-init}Lab complet : VM avec cloud-init
Section intitulée « Lab complet : VM avec cloud-init »terraform { required_version = ">= 1.11.0" required_providers { libvirt = { source = "dmacvicar/libvirt" version = "~> 0.8" } }}
provider "libvirt" { uri = "qemu:///system"}locals { vm_name = "lab-vm"}
resource "libvirt_volume" "disk" { name = "${local.vm_name}.qcow2" pool = "default" target = { format = { type = "qcow2" } } create = { content = { url = pathexpand("~/images/ubuntu-24.04-cloudimg.img") } }}
resource "libvirt_cloudinit_disk" "init" { name = "${local.vm_name}-init.iso" pool = "default" user_data = <<-EOF #cloud-config users: - name: ubuntu groups: sudo shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys: - ${trimspace(file(pathexpand("~/.ssh/id_ed25519.pub")))} EOF}
resource "libvirt_domain" "vm" { name = local.vm_name type = "kvm" memory = 512 memory_unit = "MiB" vcpu = 1
cloudinit = libvirt_cloudinit_disk.init.id
os = { type = "hvm", type_arch = "x86_64", type_machine = "q35" }
devices = { disks = [{ source = { file = { file = libvirt_volume.disk.path } } target = { dev = "vda", bus = "virtio" } }] interfaces = [{ model = { type = "virtio" } source = { network = { network = "default" } } }] }}
output "vm_name" { value = libvirt_domain.vm.name}À retenir
Section intitulée « À retenir »- Une VM libvirt nécessite deux ressources minimum :
libvirt_volume+libvirt_domain. - Le format
qcow2et le busvirtiosont les choix recommandés pour les performances. - Le chipset
q35est le standard moderne pour les guests KVM. cloud-initest indispensable pour rendre la VM accessible via SSH au premier démarrage.virsh list,virsh dominfo,virsh dumpxmlpermettent d’inspecter une VM après sa création.