
Votre terraform apply échoue à mi-chemin avec une erreur cryptique :
la VM n'a pas pu démarrer car le réseau n'était pas encore prêt. Aucune
référence entre les deux ressources n'existe dans le code, Terraform
ne peut pas déduire l'ordre correct.
Terraform construit automatiquement un graphe de dépendances à
partir des références entre ressources. Quand resource A utilise
un attribut de resource B, Terraform sait que B doit exister avant A.
Mais certaines dépendances sont comportementales, pas structurelles :
un service doit être démarré, un réseau actif, un pare-feu appliqué,
sans qu'aucune référence d'attribut ne l'exprime. C'est précisément
pour ces cas qu'existe depends_on : forcer un ordre explicite là
où le graphe implicite est aveugle.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Comment Terraform détermine l'ordre de création via les références
- La différence entre dépendance implicite et explicite
- Quand utiliser
depends_on, et quand ne pas l'utiliser - Usage sur les ressources, les modules et les
datasources - Lab KVM : réseau NAT créé avant la VM via
depends_on
Prérequis
Section intitulée « Prérequis »- Bases des ressources Terraform (Déclarer des ressources)
- Notions de providers (Providers Terraform)
Dépendances implicites
Section intitulée « Dépendances implicites »Analogie : imaginez un chantier de construction. Si le plombier a besoin d'eau courante (du réservoir), il ne peut pas commencer avant que le réservoir soit installé. Terraform voit la référence (« le chef plombier dit qu'il a besoin du réservoir ») et ordonne automatiquement les étapes. C'est une dépendance implicite.
Terraform crée automatiquement une dépendance implicite dès qu'une ressource référence un attribut d'une autre ressource.
resource "libvirt_volume" "base" { name = "vm-base.qcow2" # ...}
resource "libvirt_domain" "vm" { devices = { disks = [{ source = { file = { file = libvirt_volume.base.path } } # ↑ référence → Terraform sait que base doit exister avant vm }] }}Terraform lit cette référence et en déduit :
libvirt_volume.base→ doit être créé avantlibvirt_domain.vmlibvirt_domain.vm→ doit être détruit avantlibvirt_volume.base
C'est le cas le plus courant : pas besoin de depends_on.
Dépendances explicites avec depends_on
Section intitulée « Dépendances explicites avec depends_on »Certaines dépendances ne passent pas par des attributs HCL. Elles sont comportementales, pas structurelles. Exemples :
- Un réseau doit être opérationnel avant qu'une VM soit créée dedans
- Un utilisateur IAM doit avoir ses permissions avant qu'un job soit lancé
- Un script d'initialisation doit être terminé avant qu'une ressource soit configurée
resource "libvirt_network" "lab_net" { name = "lab12-net" forward = { mode = "nat" } ips = [{ address = "10.99.12.1", netmask = "255.255.255.0" }]}
resource "libvirt_domain" "vm" { # ... devices = { interfaces = [{ source = { network = { network = libvirt_network.lab_net.name } } # Référence au nom du réseau, mais Terraform ne sait pas que # la ressource doit être PRÊTE (pas seulement son nom connu). }] }
depends_on = [libvirt_network.lab_net] # ← force l'attente complète}Exemple : VM sur un réseau NAT dédié
Section intitulée « Exemple : VM sur un réseau NAT dédié »Structure du lab
Section intitulée « Structure du lab »# main.tf — réseau NAT + VM avec depends_onresource "libvirt_network" "lab_net" { name = "lab12-net" autostart = false
forward = { mode = "nat" }
ips = [{ address = "10.99.12.1" netmask = "255.255.255.0" dhcp = { ranges = [{ start = "10.99.12.100", end = "10.99.12.200" }] } }]}
resource "libvirt_volume" "base" { name = "lab12-vm-base.qcow2" pool = "default" target = { format = { type = "qcow2" } } create = { content = { url = "/home/bob/images/ubuntu-24.04-cloudimg.img" } }}
resource "libvirt_domain" "vm" { name = "lab12-vm" type = "kvm" memory = 512 memory_unit = "MiB" vcpu = 1
os = { type = "hvm", type_arch = "x86_64", type_machine = "q35" }
devices = { disks = [{ source = { file = { file = libvirt_volume.base.path } } target = { dev = "vda", bus = "virtio" } }] interfaces = [{ model = { type = "virtio" } source = { network = { network = libvirt_network.lab_net.name } } }] }
depends_on = [libvirt_network.lab_net] # libvirt_volume.base n'est PAS ici : la référence à .path # crée déjà une dépendance implicite — depends_on serait redondant.}Résultats réels
Section intitulée « Résultats réels »libvirt_volume.base: Creating...libvirt_network.lab_net: Creating...libvirt_network.lab_net: Creation complete after 0slibvirt_volume.base: Creation complete after 0slibvirt_domain.vm: Creating...libvirt_domain.vm: Creation complete after 0s [name=lab12-vm]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Outputs:network_gateway = "10.99.12.1"network_name = "lab12-net"vm_name = "lab12-vm"Terraform a créé libvirt_network et libvirt_volume en parallèle
(deux ressources sans dépendance entre elles), puis libvirt_domain seulement
après que les deux soient terminées.
Visualiser le graphe de dépendances
Section intitulée « Visualiser le graphe de dépendances »terraform graph | dot -Tpng > graph.pngRequiert graphviz. Chaque flèche représente une dépendance. depends_on
ajoute des flèches en pointillés.
Sans graphviz, lire le plan suffit, Terraform affiche l'ordre d'exécution :
libvirt_network.lab_net: Creating... ← 1er (pas de déps)libvirt_volume.base: Creating... ← 1er (en parallèle)libvirt_domain.vm: Creating... ← après les deux précédentsdepends_on sur les modules
Section intitulée « depends_on sur les modules »module "database" { source = "./modules/database"}
module "application" { source = "./modules/application"
depends_on = [module.database] # Tout le module database est terminé avant que # les ressources du module application soient créées.}depends_on sur les data sources
Section intitulée « depends_on sur les data sources »Un data source qui dépend d'une ressource créée dans le même plan :
resource "aws_iam_role" "lambda" { name = "lambda-role" # ...}
data "aws_iam_policy_document" "lambda" { depends_on = [aws_iam_role.lambda] # Attend que le rôle existe avant de le lire statement { actions = ["sts:AssumeRole"] principals { type = "Service", identifiers = ["lambda.amazonaws.com"] } }}## Quand NE PAS utiliser depends_on
| Situation | Solution correcte ||-----------|------------------|| Ressource B référence un attribut de A | Référence implicite (`A.attribut`) — `depends_on` inutile || Module B utilise des outputs du module A | `module.a.output_name` — dépendance implicite créée || Vous voulez un "ordre logique" sans vraie dépendance | Ne pas ajouter `depends_on` — Terraform s'en charge |
`depends_on` explicite **désactive le parallélisme** entre les ressourcesconcernées et peut produire des plans plus conservateurs (davantage devaleurs en `known after apply`, remplacements évitables). Ajouter desdépendances inutiles ralentit les apply et réduit la qualité du plan.
## Règle pratique
Poser la question : *"Si je supprimais `depends_on`, Terraform pourrait-iltenter de créer la ressource avant que sa dépendance soit opérationnelle ?"*
- **Oui** → `depends_on` justifié- **Non** → une référence d'attribut implicite suffit
## À retenir
1. Les **références** (`ressource_a.attribut`) créent des dépendances implicites automatiquement2. `depends_on` est pour les dépendances **comportementales** — non visibles dans le HCL3. Terraform crée les ressources indépendantes **en parallèle** — `depends_on` le désactive4. Sur des modules : `depends_on = [module.nom]` attend la fin de toutes les ressources du module5. Sur des data sources : utile quand la ressource source est créée dans le même plan
## Prochaines étapes
<CardGrid>
<LinkCard title="lifecycle : contrôler le remplacement des ressources" description="create_before_destroy, prevent_destroy, ignore_changes : maîtriser le cycle de vie des ressources." href="/docs/infra-as-code/provisionnement/terraform/ecrire-code/lifecycle-terraform/"/>
<LinkCard title="Votre première infrastructure" description="Créer une VM complète sur KVM avec Terraform : lab guidé de A à Z." href="/docs/infra-as-code/provisionnement/terraform/premieres-infras/premiere-infrastructure/"/>
</CardGrid>