Aller au contenu
Infrastructure as Code medium

depends_on Terraform : le dernier recours, pas le réflexe

20 min de lecture

logo terraform

Terraform ordonne les ressources tout seul, à partir des références que vous écrivez dans la configuration. Le meta-argument depends_on ne sert que pour la poignée de cas qu'aucune référence ne peut exprimer. C'est un dernier recours, pas un réflexe : posé par confort, en double d'une référence déjà présente, il n'ordonne rien de plus et rend le plan plus conservateur.

Ce guide part de la base, comment naît une dépendance implicite, puis donne le critère exact qui décide entre implicite et explicite, rend le coût de depends_on observable dans le plan JSON, et montre l'alternative replace_triggered_by. Tous les comportements ont été vérifiés sur Terraform v1.15.4 avec les providers local et null.

  • Comment une référence crée une dépendance, et ce qu'elle attend vraiment
  • Le critère qui tranche entre dépendance implicite et depends_on
  • Les rares cas où depends_on est nécessaire
  • Lire les dépendances dans le plan JSON, et voir le coût d'un depends_on de trop
  • L'alternative replace_triggered_by pour lier un remplacement

Quand une ressource référence un attribut d'une autre, Terraform en déduit l'ordre. C'est la dépendance implicite, et elle couvre l'immense majorité des cas. Ici, le serveur cite le nom du réseau :

resource "local_file" "reseau" {
filename = "reseau.txt"
content = "cidr 10.0.0.0/24"
}
resource "local_file" "serveur" {
filename = "serveur.txt"
content = "rattache a : ${local_file.reseau.filename}"
}

Le plan JSON expose cette dépendance : la section configuration liste les références de chaque expression.

Fenêtre de terminal
terraform plan -out=tfplan
terraform show -json tfplan | jq '.configuration.root_module.resources[] | select(.address=="local_file.serveur") | .expressions.content.references'
["local_file.reseau.filename", "local_file.reseau"]

Et le serveur ne porte aucun depends_on. L'ordre est pourtant garanti : Terraform crée le réseau, puis le serveur. La documentation le confirme : « Terraform analyzes expressions within a resource block to find references to other objects and treats those references as the implicit dependencies. »

Une référence attend la fin de l'amont, pas un nom

Section intitulée « Une référence attend la fin de l'amont, pas un nom »

Une idée fausse circule dans beaucoup de tutoriels : une référence n'attendrait que la connaissance d'une valeur, pas la disponibilité réelle de la ressource. C'est inexact. Une référence attend que l'amont ait fini d'être appliqué.

La preuve tient en un exemple où l'amont met du temps. La base attend deux secondes avant d'écrire un marqueur, l'app le lit :

resource "null_resource" "base" {
provisioner "local-exec" {
command = "sleep 2 && echo pret > marqueur.txt"
}
}
resource "null_resource" "app" {
triggers = { base = null_resource.base.id }
provisioner "local-exec" {
command = "cat marqueur.txt"
}
}
Fenêtre de terminal
terraform apply

L'apply réussit. Si la référence n'avait attendu qu'un « nom connu », cat marqueur.txt se serait exécuté avant que base ne l'écrive, et aurait échoué. Le succès prouve que la référence a bien attendu la fin de base. Il n'existe aucune sémantique « nom connu mais ressource pas prête ».

Le critère qui tranche : la ressource utilise-t-elle une donnée de l'amont ?

Section intitulée « Le critère qui tranche : la ressource utilise-t-elle une donnée de l'amont ? »

Voici la règle qui décide, et elle n'est pas celle qu'on croit. Le critère n'est pas « la ressource risque-t-elle de démarrer trop tôt ? » : une référence gère déjà ce cas. Le critère est :

La ressource utilise-t-elle une donnée de l'amont dans ses arguments ?

  • Oui : une référence suffit, et elle est préférable. Pas de depends_on.
  • Non, et la dépendance existe quand même (un comportement, un effet de bord) : alors, et seulement alors, depends_on.

La documentation l'énonce ainsi : « You only need to explicitly specify a dependency when a resource or module relies on another resource's behavior but does not access any of that resource's data in its arguments. »

Il reste les cas où une ressource dépend du comportement d'une autre sans utiliser aucune de ses données. Un service qui prépare un état sur le disque, par exemple, sans exposer d'attribut exploitable. Là, il n'y a rien à référencer, et depends_on devient nécessaire :

resource "null_resource" "service" {
provisioner "local-exec" {
command = "sleep 1 && touch pret.flag"
}
}
resource "null_resource" "consommateur" {
depends_on = [null_resource.service]
provisioner "local-exec" {
command = "test -f pret.flag"
}
}

L'apply réussit : pret.flag existe quand consommateur le cherche. Sans le depends_on, Terraform lancerait les deux en parallèle et la vérification échouerait, faute de la moindre référence pour ordonner.

depends_on accepte une liste de références vers des ressources ou des modules enfants du même module appelant, jamais des expressions arbitraires. Il vit aussi sur d'autres blocs que resource : module, data, et depuis les versions récentes check, ephemeral et output. Sur un output, la documentation recommande d'ajouter un commentaire expliquant pourquoi la dépendance est nécessaire.

L'erreur la plus fréquente est de poser un depends_on vers une ressource que le bloc référence déjà. Il n'ordonne alors rien de plus, mais abîme le plan. Le plan JSON permet de le repérer noir sur blanc : pour un bloc donné, comparez ses depends_on aux ressources citées dans ses references.

Fenêtre de terminal
terraform show -json tfplan | jq '.configuration.root_module.resources[] | {address, depends_on, refs: [.expressions[].references?] | flatten}'

Si une ressource apparaît à la fois dans depends_on et dans les references, le depends_on est redondant : supprimez-le. C'est le contrôle qui distingue une dépendance légitime d'un doublon de confort.

Quand le besoin n'est pas d'ordonner mais de remplacer une ressource dès qu'une autre change, depends_on n'est pas l'outil. C'est replace_triggered_by, dans le bloc lifecycle :

resource "null_resource" "app" {
lifecycle {
replace_triggered_by = [null_resource.config]
}
}

depends_on ordonne la création ; replace_triggered_by déclenche un remplacement. Le sujet est traité dans le bloc lifecycle Terraform.

Une data source accepte aussi depends_on, mais son effet est souvent mal compris. Il ne rend pas systématiquement la lecture (known after apply). Ce comportement inconditionnel appartenait à Terraform 0.12. Depuis 0.13, depends_on « configures Terraform to defer querying the data source until after it finishes operations for the specified dependency » : si l'objet amont n'a aucun changement planifié, la lecture a bien lieu au plan.

Vérifié sur 1.15.4 : sur un plan à froid, la data source apparaît dans resource_changes avec actions: ["read"] (lecture reportée) ; sur le replan qui suit l'apply, elle n'y apparaît plus. Le sujet est creusé dans les data sources Terraform.

Les problèmes de dépendance se rangent en deux familles : un ordre qui manque, et un depends_on de trop. Le tableau les sépare, avec la correction propre à chacun.

SymptômeCauseSolution
Une ressource démarre avant sa dépendanceAucune référence ni depends_on ne relie les deuxRéférencer un attribut de l'amont, ou depends_on si l'amont n'expose aucune donnée
Plan plus conservateur qu'attendu, remplacements en tropUn depends_on de confortLe supprimer s'il double une référence (contrôle plan JSON ci-dessus)
Invalid single-argument block definitionUn bloc mono-ligne à deux arguments dans l'exempleÉcrire le bloc en multi-lignes
Data source en (known after apply) inattenduElle dépend d'une ressource qui change dans ce planComportement normal depuis 0.13, pas un effet inconditionnel de depends_on
  1. Une référence crée une dépendance implicite, et elle attend que l'amont ait fini d'être appliqué, pas seulement qu'un nom soit connu.
  2. Le critère qui décide : la ressource utilise-t-elle une donnée de l'amont dans ses arguments ? Si oui, une référence suffit.
  3. depends_on est un dernier recours, pour une dépendance de comportement qu'aucune référence ne peut exprimer.
  4. Son coût est un plan plus conservateur, pas une perte de parallélisme.
  5. Un depends_on qui double une référence est redondant : le plan JSON le révèle en comparant depends_on et references.
  6. Pour remplacer au lieu d'ordonner, c'est replace_triggered_by.
  7. Sur une data source, depends_on ne force plus systématiquement le (known after apply) depuis Terraform 0.13.

Les questions ci-dessous portent sur les confusions les plus fréquentes autour de depends_on : sa redondance avec une référence, ce qu'une référence attend vraiment, et son coût réel.

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn