« Terraform crée une VM, donc elle est prête à l’emploi. »
Terraform crée la coquille : CPU, RAM, disque, réseau. Mais une VM vide n’a ni utilisateur, ni clé SSH, ni IP configurée. C’est le rôle de cloud-init — le standard d’initialisation au premier démarrage. Terraform + cloud-init = une VM qui naît déjà accessible. Et le tout, paramétré pour être reproductible à l’infini.
À la fin de ce module, tu sauras…
- Comprendre le rôle d’un template cloud-init
- Écrire une ressource VM paramétrée par des variables
- Injecter utilisateur, clé SSH et IP via cloud-init
- Récupérer des informations avec des outputs, et industrialiser avec count/for_each
01Le template cloud-init
Préparer une image « clonable »
Sur l’hôte Proxmox, on prépare une fois un template basé sur une image cloud Debian (avec cloud-init intégré). Idée générale :
Manipulewget https://cloud.debian.org/images/cloud/trixie/latest/debian-13-genericcloud-amd64.qcow2
qm create 9000 --name debian13-cloud --memory 2048 --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci
qm set 9000 --scsi0 local-lvm:0,import-from=/chemin/debian-13-genericcloud-amd64.qcow2
qm set 9000 --ide2 local-lvm:cloudinit --boot order=scsi0 --serial0 socket --vga serial0
qm template 9000Comprends pourquoi un template, et cloud-init
Une image cloud embarque cloud-init : au premier boot, elle lit une configuration (utilisateur, clés SSH, réseau, paquets) et s’auto-configure. C’est le standard d’initialisation des VMs dans tout le cloud (AWS l’appelle « user data », Azure « custom data » — même principe). Le template, lui, garantit que chaque VM part d’une base identique. Terraform clone le template et fournit la config cloud-init : la VM naît prête.
02Les variables : décrire une VM générique
Paramétrer plutôt que coder en dur
Dans variables.tf, ajoute de quoi décrire une VM sans rien figer :
variable "vm_name" { type = string }
variable "vm_cores" { type = number, default = 2 }
variable "vm_memory" { type = number, default = 2048 }
variable "vm_ip" { type = string }
variable "target_node" { type = string, default = "pve" }
variable "ssh_public_key" { type = string }Comprends pourquoi tout paramétrer
En externalisant nom, CPU, RAM, IP en variables, le même fichier décrit n’importe quelle VM : il suffit de changer les valeurs. C’est la base de la réutilisation — une seule définition, des dizaines de machines. Le code décrit un gabarit, les variables le spécialisent. Principe identique sur tout provider.
03La ressource VM
Cloner le template, injecter cloud-init
Dans un fichier vm.tf :
resource "proxmox_virtual_environment_vm" "soria_vm" {
name = var.vm_name
node_name = var.target_node
clone {
vm_id = 9000
}
cpu { cores = var.vm_cores }
memory { dedicated = var.vm_memory }
initialization {
ip_config {
ipv4 {
address = "${var.vm_ip}/24"
gateway = "192.168.10.1"
}
}
user_account {
username = "soria"
keys = [var.ssh_public_key]
}
}
network_device {
bridge = "vmbr1"
}
}Comprends chaque bloc, et le lien cloud-init
clone part du template 9000. cpu/memory dimensionnent. Le bloc initialization = la config cloud-init : ip_config (IP statique sur ton LAN), user_account (utilisateur + clé SSH). network_device raccorde la VM au bon bridge (ton réseau interne de la Phase 2). Résultat : une VM clonée, avec IP fixe, accessible en SSH par ta clé — dès le premier boot.
04Les outputs : récupérer l’information
Faire ressortir ce dont tu as besoin
Dans outputs.tf :
output "vm_id" {
value = proxmox_virtual_environment_vm.soria_vm.vm_id
}
output "vm_ssh" {
value = "ssh soria@${var.vm_ip}"
}Manipuleterraform apply -var vm_name="test-tf" -var vm_ip="192.168.10.50" -var ssh_public_key="$(cat ~/.ssh/id_ed25519.pub)"ObserveApply complete! Resources: 1 added.
Outputs:
vm_id = 100
vm_ssh = "ssh soria@192.168.10.50"ssh soria@192.168.10.50 — tu entres, grâce à la clé injectée par cloud-init.Comprends à quoi servent les outputs
Les outputs exposent des valeurs calculées après création (ID, IP, URL…). Utile pour toi (récupérer une info), mais surtout pour chaîner : ces valeurs peuvent alimenter un autre outil — par exemple générer l’inventaire Ansible (module 7.6). L’output est le point de sortie structuré de Terraform.
05Industrialiser : plusieurs VMs
De une VM à une flotte, avec for_each
La vraie puissance : décrire plusieurs machines sans dupliquer le code. Exemple de définition d’un parc :
Manipulevariable "vms" {
type = map(object({ ip = string, cores = number, memory = number }))
default = {
"worker-1" = { ip = "192.168.10.61", cores = 2, memory = 4096 }
"worker-2" = { ip = "192.168.10.62", cores = 2, memory = 4096 }
}
}Puis for_each sur la ressource :
resource "proxmox_virtual_environment_vm" "fleet" {
for_each = var.vms
name = each.key
node_name = var.target_node
clone { vm_id = 9000 }
cpu { cores = each.value.cores }
memory { dedicated = each.value.memory }
# ... initialization avec each.value.ip ...
}Observeterraform plan montrerait 2 VMs à créer d’un coup. Ajoute une entrée à la map → une VM de plus. Supprime-la → Terraform détruit la bonne. Toute une flotte, décrite en quelques lignes.Comprends count vs for_each
count crée N copies indexées (0,1,2…) — simple mais fragile si l’ordre change. for_each crée une ressource par clé d’une map/set — chaque VM a une identité stable (son nom), idéale pour un parc nommé. C’est ainsi qu’on gère des dizaines de machines sans copier-coller : la description reste courte, le state suit chaque instance. Concept transposable à tout provider.
✓Ce que tu retiens
Terraform crée la VM ; cloud-init l’initialise (utilisateur, clé SSH, IP) dès le premier boot, à partir d’un template. Tout est paramétré par variables (un gabarit réutilisable), les outputs exposent les infos utiles, et for_each industrialise une flotte entière. Tu sais désormais provisionner de l’infrastructure reproductible — le geste est le même sur Proxmox, AWS ou Azure.
Provisionne, et vois plus grand
À faire
- Prépare (ou vérifie) un template cloud-init Debian 13 sur Proxmox.
- Écris la ressource VM paramétrée + variables + outputs.
- Crée une VM, prouve l’accès SSH par la clé injectée (cloud-init a fonctionné).
- Passe à
for_each: décris 2 VMs, applique, puis ajoute-en une 3e en une ligne. - Fais un
destroyciblé et observe le plan. - Défi (indépendance du provider) : sur un cloud gratuit de ton choix (beaucoup offrent un palier gratuit), écris un petit Terraform qui déploie une VM avec le provider correspondant (ex.
aws_instance,azurerm_linux_virtual_machine, ou une autre plateforme). Constate queinit/plan/applyet la logique de state sont identiques — seuls le provider et les noms de ressources changent.
?Auto-évaluation
1. Que fait cloud-init, et pourquoi Terraform seul ne suffit pas pour une VM prête ?
Terraform crée la coquille (CPU/RAM/disque/réseau) ; cloud-init l’initialise au premier boot (utilisateur, clé SSH, IP). Sans cloud-init, la VM serait vide et inaccessible.
2. À quoi servent les outputs ?
À exposer des valeurs calculées après création (ID, IP…), utiles pour l’utilisateur ou pour chaîner vers un autre outil (ex. inventaire Ansible).
3. Pourquoi for_each plutôt que du copier-coller pour une flotte ?
Une seule définition crée une ressource par entrée, chacune avec une identité stable. On gère des dizaines de VMs sans dupliquer le code, et le state suit chaque instance.