Aller au contenu
Infrastructure as Code medium

Déclarer des ressources Terraform : bloc resource et cycle de vie

20 min de lecture

logo terraform

Le bloc resource est la brique de base de Terraform : il déclare un objet à créer et à maintenir. Le déclarer est simple. Ce qui compte vraiment, et ce que l'examen interroge, c'est de savoir lire, avant d'appliquer, ce que Terraform va faire à cette ressource : la créer, la mettre à jour en place, la remplacer, ou la détruire.

Ce guide part de la base, la syntaxe et l'adressage, puis montre comment les références ordonnent les ressources, et enfin comment lire les quatre opérations du cycle de vie dans le plan au format JSON. Les exemples ont été vérifiés sur Terraform v1.15.4 avec local, random et terraform_data, sans cloud.

  • La syntaxe d'un bloc resource : type, nom, arguments
  • Pourquoi le couple type + nom est l'adresse dans le state
  • Comment une référence ordonne les ressources, sans depends_on
  • Les quatre opérations du cycle de vie, et leur signature dans le plan
  • terraform_data, la ressource intégrée sans provider
  • Lire le plan et le state de façon structurée (-json)

Un bloc resource déclare un objet que Terraform crée, met à jour et détruit. Sa syntaxe tient en trois parties :

resource "local_file" "rapport" {
filename = "rapport.txt"
content = "bonjour"
}
  • local_file est le type, fourni par un provider (ici local). Une exception : terraform_data est un type intégré, il n'appartient à aucun provider.
  • rapport est le nom local.
  • Le corps contient les arguments de l'objet.

On référence la ressource par local_file.rapport, et ses attributs par local_file.rapport.<attribut>.

Le couple type + nom n'est pas qu'un alias de code : c'est l'adresse de la ressource dans le fichier d'état. La documentation le dit : « Terraform uses the resource type and name as the resource's address in your workspace's state file. »

La conséquence est concrète et surprend souvent : renommer une ressource détruit l'objet et le recrée, parce que Terraform voit l'ancienne adresse disparaître et une nouvelle apparaître. Pour renommer sans détruire, il faut un bloc moved, traité dans le lab de migration for_each.

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 suffit dans l'immense majorité des cas :

resource "random_pet" "hote" {
length = 2
}
resource "local_file" "fiche" {
filename = "fiche-${random_pet.hote.id}.txt"
content = "hote=${random_pet.hote.id}\n"
}

local_file.fiche référence random_pet.hote.id : Terraform crée l'hôte, puis la fiche. Aucun depends_on n'est nécessaire, et en ajouter un ici serait redondant. Le meta-argument depends_on ne sert qu'aux dépendances de comportement qu'aucune référence ne peut exprimer : voir depends_on en Terraform.

Voici le cœur du sujet, et ce que l'examen interroge. Terraform ne fait que quatre choses à une ressource, et chacune a une signature dans le plan JSON.

Opérationactions dans le plan
Créer["create"]
Mettre à jour en place["update"]
Remplacer (détruire puis créer)["delete", "create"]
Détruire["delete"]

Une cinquième valeur, ["no-op"], signale qu'il n'y a rien à faire. Tout le sujet consiste à distinguer une mise à jour en place d'un remplacement : l'une modifie l'objet, l'autre le recrée.

Ce petit montage suffit à provoquer les deux opérations qui comptent, une mise à jour en place et un remplacement, sans aucun provider distant :

variable "niveau" {
type = string
default = "beta"
}
variable "cycle" {
type = number
default = 1
}
resource "random_pet" "serie" {
length = 2
keepers = { cycle = var.cycle }
}
resource "terraform_data" "jeton" {
input = var.niveau
triggers_replace = random_pet.serie.id
}

terraform_data est une ressource intégrée qui offre le cycle de vie complet sans aucun provider : son argument input se met à jour en place, et triggers_replace force un remplacement quand la valeur suivie change.

Changez le niveau. L'argument input change, mais rien n'impose de recréer :

Fenêtre de terminal
terraform apply -auto-approve
terraform plan -var 'niveau=stable' -out=tfplan
terraform show -json tfplan | jq -c '.resource_changes[] | select(.address=="terraform_data.jeton") | .change.actions'
["update"]

["update"] : l'objet est modifié, pas recréé. C'est le cas le moins coûteux.

Changez le cycle. Les keepers en dépendent, donc random_pet.serie est remplacé, son id change, et le triggers_replace du jeton déclenche à son tour un remplacement :

Fenêtre de terminal
terraform plan -var 'cycle=2' -out=tfplan
terraform show -json tfplan | jq -c '.resource_changes[] | select(.address=="terraform_data.jeton") | .change.actions'
["delete", "create"]

["delete", "create"] : détruit puis recréé. Ce n'est pas anodin, l'objet est neuf. Pour inverser cet ordre et supprimer la fenêtre où l'objet n'existe plus, c'est create_before_destroy, traité dans le bloc lifecycle Terraform.

terraform state list et terraform state show produisent une sortie humaine, pratique à lire mais non contractuelle. Pour un script ou un contrôle, seules les formes structurées sont stables :

Fenêtre de terminal
terraform show -json | jq '.values.root_module.resources[] | {address, mode}'
terraform plan -detailed-exitcode # 0 = aucun changement, 2 = des changements
terraform output -json

terraform plan -detailed-exitcode rend 0 quand la configuration est stable, 2 quand des changements restent à appliquer : c'est le test d'idempotence de tout workflow en automation.

Un bloc provisioner exécute une commande locale ou distante lors de la création ou de la destruction. La documentation officielle le déconseille : « We recommend using configuration management tools or other means to perform actions on the local or remote machine instead of using the provisioner block. » Réservez-le aux cas qu'aucune ressource de provider ne couvre.

Ces symptômes se lisent tous dans le plan, avant l'apply. Le tableau associe chaque signature d'action à ce qu'elle signifie réellement.

SymptômeCauseSolution
Une ressource est remplacée alors qu'on attendait une mise à jourUn attribut modifié ne peut pas être changé en placeNormal si l'API distante l'impose ; le plan montre ["delete", "create"]
Une ressource est détruite puis recréée après un simple renommageLe nom fait partie de l'adresse dans le stateUtiliser un bloc moved pour renommer sans détruire
Invalid single-argument block definitionUn bloc mono-ligne à deux argumentsÉcrire le bloc en multi-lignes, un argument par ligne
Resource already existsL'objet existe hors de TerraformL'importer avec un bloc import {}
Un depends_on ajouté ne change rienIl double une référence déjà présenteLe supprimer : la référence ordonne déjà
  1. Un bloc resource a un type (du provider, sauf terraform_data) et un nom local.
  2. Le couple type + nom est l'adresse dans le state : renommer détruit et recrée, sauf bloc moved.
  3. Une référence ordonne les ressources ; depends_on n'est qu'un dernier recours.
  4. Terraform ne fait que quatre opérations, chacune avec sa signature : ["create"], ["update"], ["delete", "create"], ["delete"].
  5. Distinguer mise à jour en place et remplacement est le point clé, et le plan JSON le donne avant l'apply.
  6. terraform_data offre le cycle de vie complet sans provider.
  7. Les formes -json et plan -detailed-exitcode sont les seules stables pour un contrôle.

Les questions ci-dessous reprennent les points qui reviennent le plus souvent : l'adresse comme clé du state, le choix entre référence et depends_on, et la lecture des opérations dans le plan.

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