Aller au contenu principal
TerraformInfrastructure as CodeFormation

Le State : comprendre l'état Terraform

30 min de lecture Terraform — Chapitre 5

Comprends le state Terraform : fichier local vs backend distant (S3, Consul), locking, import de ressources et bonnes pratiques de gestion du state.

Le state est le fichier le plus important de ton projet Terraform — et aussi le plus dangereux. C’est la mémoire qui connecte ton code à l’infrastructure réelle. Sans lui, Terraform est aveugle. Ce chapitre explique comment il fonctionne, pourquoi il faut le protéger, et comment le gérer correctement en équipe.

Le state, c’est quoi exactement ?

Le fichier terraform.tfstate est un JSON qui mappe chaque ressource déclarée dans ton code HCL à l’objet réel dans le cloud. Quand tu lances terraform plan, voici ce qui se passe :

  1. Terraform lit ta configuration .tf
  2. Il lit le state actuel
  3. Il interroge l’API du provider pour l’état réel
  4. Il calcule le diff entre les trois

Sans ce mapping, Terraform ne peut pas savoir si un serveur existe déjà, s’il a changé, ou s’il faut le créer. Le state contient aussi des données sensibles : IDs, adresses IP, et parfois des mots de passe ou clés API.

💡 Analogie : le state, c’est la base de données interne de Terraform. Ton code .tf décrit l’état souhaité. L’API cloud est l’état réel. Le state est le pont entre les deux.

State local vs state distant

Le backend local — simple mais risqué

Par défaut, le state vit dans un fichier terraform.tfstate à la racine du projet. Zéro configuration, parfait pour un lab solo.

Les problèmes arrivent vite :

  • Pas de partage — ton collègue n’a pas le fichier
  • Pas de locking — deux apply simultanés = corruption garantie
  • Pas de backup — un rm accidentel = tu perds la correspondance code ↔ infra

Le backend distant — le standard en équipe

Un backend distant stocke le state sur un service partagé. Le plus courant est S3 avec DynamoDB pour le locking :

terraform {
  backend "s3" {
    bucket         = "mon-projet-terraform-state"
    key            = "prod/infra/terraform.tfstate"
    region         = "eu-west-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

La table DynamoDB assure le locking — un seul apply à la fois peut écrire dans le state. Crée-la avec hash_key = "LockID" et billing_mode = "PAY_PER_REQUEST".

🔥 Le problème de la poule et l’œuf : le bucket S3 et la table DynamoDB doivent exister avant de configurer le backend. Crée-les dans un projet Terraform séparé avec un state local. C’est la convention standard.

Pour migrer du local au distant, lance terraform init -migrate-state après avoir ajouté le bloc backend. Terraform copie le state et supprime le fichier local.

Le locking : éviter les catastrophes

Le locking empêche deux personnes d’écrire dans le state en même temps. Sans lui, un apply peut écraser les changements d’un autre — corruption silencieuse.

Quand le lock est actif et qu’un second apply tente de s’exécuter :

Error: Error acquiring the state lock
Lock Info:
  ID:        a1b2c3d4-e5f6-7890-abcd-ef1234567890
  Operation: OperationTypeApply
  Who:       dany@workstation
  Created:   2026-03-19 22:00:00 UTC

En cas de crash qui laisse un lock orphelin :

terraform force-unlock a1b2c3d4-e5f6-7890-abcd-ef1234567890

⚠️ N’utilise force-unlock que si tu es certain qu’aucune opération n’est en cours. Sinon, tu crées exactement le problème que le lock est censé prévenir.

Workspaces : un state par environnement

Les workspaces permettent d’avoir plusieurs states distincts avec la même configuration. Chaque workspace a son propre fichier state.

Les commandes essentielles : terraform workspace new staging (créer), workspace select prod (basculer), workspace list (lister).

Dans ta config, terraform.workspace retourne le nom du workspace actif :

locals {
  config = {
    dev     = { type = "cx22", count = 1 }
    staging = { type = "cx22", count = 2 }
    prod    = { type = "cx32", count = 3 }
  }
  env = local.config[terraform.workspace]
}

resource "hcloud_server" "app" {
  count       = local.env.count
  name        = "app-${terraform.workspace}-${count.index}"
  server_type = local.env.type
  image       = "ubuntu-24.04"
}

💡 Quand utiliser les workspaces : environnements quasi identiques avec peu de divergence. Quand ne PAS les utiliser : environnements très différents (la prod a un WAF, pas le dev) — préfère des répertoires séparés.

Import : intégrer des ressources existantes

Tu as des serveurs créés manuellement ou par un autre outil ? terraform import les rattache au state sans les recréer.

Méthode classique (CLI)

  1. Écris le bloc resource correspondant dans ta config
  2. Importe avec la commande CLI
  3. Ajuste les attributs jusqu’à ce que plan montre zéro changement
terraform import hcloud_server.legacy 58712345
terraform plan  # Ajuste main.tf jusqu'à "No changes"

Méthode moderne (Terraform 1.5+)

Le bloc import est déclaratif et peut générer le code automatiquement :

import {
  to = hcloud_server.legacy
  id = "58712345"
}
# Puis : terraform plan -generate-config-out=generated.tf
# Terraform génère le bloc resource correspondant

Tu n’as plus qu’à nettoyer le code généré et l’intégrer. C’est un gain de temps énorme pour importer 50 ressources d’un coup.

Cas entreprise : migration d’une infra manuelle

Une startup a 15 serveurs créés à la main sur Hetzner. Aucune documentation, des configs qui driftent, et un SRE qui est le seul à connaître l’infra (le fameux “bus factor” de 1).

Le plan de migration :

  1. Inventaire — lister toutes les ressources via l’API Hetzner (hcloud server list)
  2. Squelette — écrire les blocs resource correspondants
  3. Importterraform import pour chaque ressource
  4. Ajustement — boucle plan → correction jusqu’à zéro diff
  5. Backend distant — migrer le state vers S3 avec locking
  6. CI/CD — pipeline GitLab qui exécute plan sur chaque MR

🎯 Résultat : en 2 semaines, toute l’infra est sous Terraform. Le bus factor passe de 1 à 5. Les changements sont reviewés, versionnés, et réversibles. Le SRE dort mieux.

Les pièges du state

⚠️ Commiter le state dans Git — Le piège numéro 1. Le state contient des données sensibles. Ajoute toujours *.tfstate et *.tfstate.backup au .gitignore.

⚠️ Modifier le state à la main — Ne modifie jamais le JSON directement. Utilise les commandes dédiées :

terraform state mv hcloud_server.old hcloud_server.new  # Renommer
terraform state rm hcloud_server.temp                    # Retirer du state
terraform state pull > backup.tfstate                    # Backup
terraform state push backup.tfstate                      # Restaurer

⚠️ Drift silencieux — Si quelqu’un modifie une ressource dans la console web, le state ne le sait pas. Au prochain plan, Terraform peut écraser le changement manuel. Lance terraform plan régulièrement (ou en cron) pour détecter les drifts.

⚠️ State partagé sans locking — Sur un backend S3 compatible (Infomaniak, MinIO) sans DynamoDB, il n’y a pas de locking natif. Compense avec une CI/CD qui sérialise les apply (un seul pipeline à la fois).

Résumé

Le state est le cœur de Terraform — le fichier qui connecte ton code à la réalité :

  • State local = fichier .tfstate en local, OK pour le prototypage solo
  • State distant = S3, GCS, Terraform Cloud — le standard en équipe
  • Locking = DynamoDB ou équivalent — empêche les écritures concurrentes
  • Workspaces = un state par environnement avec la même config
  • Import = rattacher des ressources existantes au state (CLI ou bloc import)
  • Règles d’or = ne jamais commiter le state, ne jamais le modifier à la main, toujours activer le locking

Dans le prochain chapitre, on structure le code avec les modules Terraform — le mécanisme de réutilisation qui transforme des scripts en bibliothèque d’infrastructure.

🖥️ Pratique sur ton propre serveur

Pour suivre Terraform en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés