
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.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- 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_onest nécessaire - Lire les dépendances dans le plan JSON, et voir le coût d'un
depends_onde trop - L'alternative
replace_triggered_bypour lier un remplacement
Prérequis
Section intitulée « Prérequis »- Ressources et attributs (déclarer des ressources Terraform)
- Terraform 1.15.x, la série stable courante
Une référence crée déjà une dépendance
Section intitulée « Une référence crée déjà une dépendance »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.
terraform plan -out=tfplanterraform 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" }}terraform applyL'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. »
depends_on : quand la référence ne suffit pas
Section intitulée « depends_on : quand la référence ne suffit pas »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.
Le depends_on de confort, et comment le repérer
Section intitulée « Le depends_on de confort, et comment le repérer »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.
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.
Une alternative : replace_triggered_by
Section intitulée « Une alternative : replace_triggered_by »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.
depends_on sur une data source
Section intitulée « depends_on sur une data source »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.
Dépannage
Section intitulée « Dépannage »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ôme | Cause | Solution |
|---|---|---|
| Une ressource démarre avant sa dépendance | Aucune référence ni depends_on ne relie les deux | Ré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 trop | Un depends_on de confort | Le supprimer s'il double une référence (contrôle plan JSON ci-dessus) |
Invalid single-argument block definition | Un bloc mono-ligne à deux arguments dans l'exemple | Écrire le bloc en multi-lignes |
Data source en (known after apply) inattendu | Elle dépend d'une ressource qui change dans ce plan | Comportement normal depuis 0.13, pas un effet inconditionnel de depends_on |
À retenir
Section intitulée « À retenir »- 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.
- 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.
depends_onest un dernier recours, pour une dépendance de comportement qu'aucune référence ne peut exprimer.- Son coût est un plan plus conservateur, pas une perte de parallélisme.
- Un
depends_onqui double une référence est redondant : le plan JSON le révèle en comparantdepends_onetreferences. - Pour remplacer au lieu d'ordonner, c'est
replace_triggered_by. - Sur une data source,
depends_onne force plus systématiquement le(known after apply)depuis Terraform 0.13.
FAQ : questions fréquentes
Section intitulée « FAQ : questions fréquentes »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.
La réponse est non
Quand une ressource référence un attribut d'une autre, Terraform en déduit l'ordre tout seul. C'est la dépendance implicite, et elle couvre l'immense majorité des cas.resource "local_file" "serveur" {
filename = "serveur.txt"
content = "rattache a : ${local_file.reseau.filename}"
}
Le coût du depends_on de trop
Ajouterdepends_on = [local_file.reseau] ici n'ordonne rien de plus, mais rend le plan plus conservateur : « it can cause Terraform to create more conservative plans that replace more resources than necessary. »Une idée fausse répandue
Beaucoup de tutoriels affirment qu'une référence n'attend que la connaissance d'une valeur. C'est inexact : elle attend que l'amont ait fini d'être appliqué.La preuve
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"
}
}
L'apply réussit. Si la référence n'avait attendu qu'un nom connu, cat marqueur.txt aurait échoué avant l'écriture. Vérifié sur Terraform 1.15.4.La bonne question
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. La question 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
depends_on.
La formulation officielle
« 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. »Un coût mal attribué
Une dépendance implicite et undepends_on ordonnent de la même façon : Terraform traite les ressources « in dependency order and in parallel when possible » dans les deux cas.Le vrai coût
Ce n'est pas le parallélisme perdu, c'est un plan plus conservateur :depends_on peut entraîner le remplacement de plus de ressources que nécessaire. C'est précisément ce qui en fait un dernier recours.La preuve est dans le plan JSON
La sectionconfiguration expose, pour chaque bloc, ses depends_on et les references de ses expressions.terraform show -json tfplan | jq '.configuration.root_module.resources[] | {address, depends_on, refs: [.expressions[].references?] | flatten}'
La règle
Si une ressource apparaît à la fois dansdepends_on et dans les references d'un bloc, le depends_on est redondant : supprimez-le. C'est le contrôle qui distingue une dépendance légitime d'un doublon de confort.Un comportement de Terraform 0.12
Le report 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 ».La règle actuelle
Si l'objet amont n'a aucun changement planifié, la lecture a lieu au plan, malgré ledepends_on.Vérifié sur Terraform 1.15.4 : sur un plan à froid, la data source apparaît dans resource_changes avec actions: ["read"] ; sur le replan après apply, elle n'y apparaît plus.Deux besoins distincts
depends_on ordonne la création : la ressource aval est appliquée après l'amont.replace_triggered_by remplace : dès que la cible change, la ressource est recréée.resource "null_resource" "app" {
lifecycle {
replace_triggered_by = [null_resource.config]
}
}
Comment choisir
Si le besoin est « appliquer après », c'estdepends_on. Si le besoin est « recréer quand ceci change », c'est replace_triggered_by, dans le bloc lifecycle.Pour aller plus loin
Section intitulée « Pour aller plus loin »- Le style guide Terraform : Les conventions qui évitent d'écrire un depends_on là où une référence suffit.
- Quiz Écrire du code Terraform : Un contrôle des acquis sur les méta-arguments et les dépendances entre blocs.
- Déboguer un terraform apply : La lecture d'un plan quand l'ordre d'exécution ne correspond pas à l'attendu.