Aller au contenu
Infrastructure as Code medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

Déclarer des ressources Terraform : le bloc resource {}

10 min de lecture

logo terraform

Sans bloc resource {}, Terraform ne crée rien. C’est l’unité de base de tout projet : chaque resource {} demande à Terraform de créer, mettre à jour ou détruire un objet précis — une VM, un volume, un bucket, une règle DNS.

Mais l’essentiel n’est pas seulement la syntaxe du bloc : c’est la façon dont les ressources se référencent mutuellement. Quand une libvirt_domain utilise libvirt_volume.disk.path, Terraform détecte automatiquement une dépendance et crée le volume avant la VM. Ce mécanisme de dépendances implicites — déduit des références dans le code, pas déclaré explicitement — est ce qui rend Terraform déclaratif et fiable. Le comprendre évite les erreurs d’ordre de création et les depends_on inutiles.

  • Syntaxe d’un bloc resource {} : type, nom local, attributs
  • Référencer une ressource depuis une autre : type.nom.attribut
  • Dépendances implicites : Terraform les détecte via les références
  • depends_on : forcer une dépendance quand il n’y a pas de référence
  • terraform state show : inspecter ce que Terraform a créé

Pensez à une structure de données classique :

# Déclarer une structure
vm = {
"name": "lab-vm",
"memory": 512,
"disk": "lab-vm.qcow2"
}
# Référencer depuis ailleurs
vm_info = f"created {vm['name']} with {vm['memory']}MB"

En Terraform, un bloc resource {} fait exactement cela : vous déclarez une structure (une VM, un volume, un réseau), lui donnez un nom local, puis le référencez depuis d’autres ressources.

resource "libvirt_volume" "disk" {
name = "lab04-vm.qcow2"
pool = "default"
}

Trois éléments fixes :

ÉlémentValeur dans l’exempleRôle
Mot-cléresourceToujours resource
Type de ressource"libvirt_volume"Définit quel objet créer (fourni par le provider)
Nom local"disk"Alias HCL utilisé dans votre code pour référencer cette instance

Le type de ressource suit toujours le format "provider_type" : libvirt_volume, libvirt_domain, aws_instance, google_compute_instance

Le nom local ("disk") est libre — il ne correspond à aucun nom sur la plateforme. C’est vous qui le choisissez pour organiser votre code.

Cet exemple crée deux ressources : un volume disque, puis une VM qui l’utilise.

main.tf
# Ressource 1 : le disque
resource "libvirt_volume" "disk" {
name = "${var.vm_name}.qcow2"
pool = var.pool
target = {
format = { type = "qcow2" }
}
create = {
content = { url = var.image_path }
}
}
# Ressource 2 : la VM — utilise le chemin du disque
resource "libvirt_domain" "vm" {
name = var.vm_name
memory = var.memory
memory_unit = "MiB"
vcpu = 1
devices = {
disks = [
{
source = {
file = {
file = libvirt_volume.disk.path # ← référence à ressource 1
}
}
target = { dev = "vda", bus = "virtio" }
}
]
}
depends_on = [libvirt_volume.disk]
}

Résultat du terraform apply — les ressources sont créées dans le bon ordre :

libvirt_volume.disk: Creating...
libvirt_volume.disk: Creation complete after 0s [id=/var/lib/libvirt/images/lab04-vm.qcow2]
libvirt_domain.vm: Creating...
libvirt_domain.vm: Creation complete after 0s [name=lab04-vm]
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
Outputs:
disk_path = "/var/lib/libvirt/images/lab04-vm.qcow2"

Pour utiliser un attribut d’une ressource dans une autre, la syntaxe est :

type_de_ressource.nom_local.attribut

Dans notre lab :

libvirt_volume.disk.path
# ↑ ↑ ↑
# type nom attribut exposé par le provider

Cette référence crée automatiquement une dépendance implicite : Terraform sait qu’il doit créer libvirt_volume.disk avant libvirt_domain.vm puisque la VM a besoin du chemin du disque.

Le graphe de dépendances généré par terraform graph le confirme :

"libvirt_domain.vm" -> "libvirt_volume.disk"

La flèche pointe vers la dépendance : libvirt_domain.vm dépend de libvirt_volume.disk.

C’est la façon normale de gérer les dépendances. Terraform la détecte automatiquement à partir des références type.nom.attribut dans le code :

file = libvirt_volume.disk.path # Terraform voit la ref → dépendance implicite

Quand il n’y a pas de référence directe mais qu’une ressource doit quand même attendre une autre, utilisez depends_on :

resource "libvirt_domain" "vm" {
# ...
depends_on = [libvirt_volume.disk]
}

depends_on s’écrit avec une liste de références de ressources (sans guillemets, sans attribut).

Après un apply, le state enregistre les attributs réels de chaque ressource :

Fenêtre de terminal
terraform state list
libvirt_domain.vm
libvirt_volume.disk

Pour inspecter une ressource en détail :

Fenêtre de terminal
terraform state show libvirt_volume.disk
# libvirt_volume.disk:
resource "libvirt_volume" "disk" {
allocation = 185401344
capacity = 3758096384
id = "/var/lib/libvirt/images/lab04-vm.qcow2"
key = "/var/lib/libvirt/images/lab04-vm.qcow2"
name = "lab04-vm.qcow2"
path = "/var/lib/libvirt/images/lab04-vm.qcow2"
pool = "default"
target = {
format = {
type = "qcow2"
}
path = "/var/lib/libvirt/images/lab04-vm.qcow2"
}
}

Les attributs affichés par terraform state show sont ceux qui peuvent être référencés dans type.nom.attribut. Ici, libvirt_volume.disk.path renvoie /var/lib/libvirt/images/lab04-vm.qcow2.

Dans le plan, certains attributs affichent (known after apply) :

+ path = (known after apply)

Cela signifie que la valeur est assignée par la plateforme au moment de la création — Terraform ne peut pas la connaître à l’avance. Pour les références entre ressources, Terraform gère cette incertitude en créant d’abord la ressource source avant d’utiliser sa valeur.

Les meta-arguments s’appliquent à tout bloc resource {} quelle que soit la ressource. Ils modifient le comportement de Terraform plutôt que la ressource elle-même :

Meta-argumentRôle
depends_onDépendance explicite sans référence d’attribut
countCréer N copies de la ressource
for_eachCréer une copie par élément d’une map ou d’un set
providerChoisir une instance de provider (alias)
lifecycleContrôler le comportement create/update/destroy

count et for_each sont couverts dans leurs guides dédiés. lifecycle sera abordé dans le guide sur le cycle de vie des ressources.

Les ressources vont dans main.tf. Pour les projets plus longs, on peut les séparer par thème (network.tf, compute.tf…) — tout fichier .tf dans le même dossier fait partie du même module.

mon-projet/
├── main.tf ← libvirt_volume.disk + libvirt_domain.vm
├── variables.tf ← variables d'entrée
├── outputs.tf ← disk_path, vm_id
└── versions.tf ← terraform {} + required_providers
SymptômeCause probableSolution
Error: Reference to undeclared resourceFaute de frappe dans type.nomVérifier le type et le nom local exacts
(known after apply) bloquant un planAttribut inconnu avant créationNormal — Terraform gère l’ordre automatiquement
Ressource créée dans le mauvais ordreDépendance manquanteAjouter une référence ou depends_on
Error: Resource already existsRessource présente hors TerraformUtiliser terraform import
  1. resource "type" "nom_local" {} — le type vient du provider, le nom local est libre
  2. type.nom.attribut référence un attribut d’une autre ressource
  3. Les références créent des dépendances implicites — Terraform respecte l’ordre
  4. depends_on gère les dépendances comportementales sans référence d’attribut
  5. terraform state show type.nom affiche les attributs réels d’une ressource après apply
  6. (known after apply) est normal — ces valeurs sont résolues au moment de la création
  7. Tous les fichiers .tf d’un même dossier forment un seul module

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn