Ressources, providers et état

Première leçon du cours Infrastructure as code avec Terraform, en accès libre : environ 18 minutes, 3 exercices et 3 questions de quiz. C'est la leçon de base du catalogue ; dans l'espace étudiant, elle est réécrite pour ton profil.

Objectifs

  • Décrire une infrastructure sous forme de fichiers HCL déclaratifs
  • Enchaîner le cycle init, plan, apply et destroy en lisant correctement le plan
  • Comprendre le rôle du fichier d'état et le stocker dans un backend distant verrouillé

Infrastructure as code déclarativeProvidersCycle init, plan, apply, destroyFichier d'état et backend

Dans le cours précédent, vous avez créé une base managée, un bucket et un service de conteneurs en cliquant dans une console ou en tapant des commandes. Cela fonctionne une fois. Mais comment recréer exactement la même chose pour la préproduction ? Comment savoir qui a modifié une règle de pare-feu, et quand ? L’infrastructure as code (IaC) répond à ces questions : l’infrastructure est décrite dans des fichiers texte, versionnés dans Git, relus en revue de code et appliqués par un outil.

Terraform (et son fork open source OpenTofu, compatible pour l’essentiel de ce cours) est l’outil d’IaC le plus répandu pour piloter plusieurs clouds avec un même langage, le HCL (HashiCorp Configuration Language).

Une approche déclarative

Vous ne décrivez pas les étapes (« crée un bucket, puis active le versionnage »), mais l’état voulu (« il existe un bucket versionné nommé ainsi »). Terraform compare cet état voulu à ce qui existe et calcule lui-même les actions. Relancer la même configuration ne crée pas de doublon : si tout est déjà conforme, il n’y a rien à faire.

Un premier fichier main.tf

terraform {
  required_version = ">= 1.6"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "eu-west-3"   # Paris
}

resource "aws_s3_bucket" "exports" {
  bucket = "atelier-nova-exports-prod"
  tags = {
    projet = "exports"
    gere_par = "terraform"
  }
}
  • Le bloc terraform fixe la version de Terraform et des providers.
  • Un provider est un plugin qui traduit vos ressources en appels d’API (AWS, Google Cloud, Azure, Scaleway, GitHub…). Il existe aussi des providers utilitaires comme hashicorp/local (fichiers locaux) et hashicorp/random (valeurs aléatoires), parfaits pour s’entraîner sans compte cloud.
  • Un bloc resource "TYPE" "NOM" déclare un objet. Son adresse est TYPE.NOM, ici aws_s3_bucket.exports. Le nom local sert à le référencer ailleurs : aws_s3_bucket.exports.arn.

Le cycle de travail

terraform init       # télécharge les providers, crée .terraform/ et .terraform.lock.hcl
terraform plan       # calcule ce qui va changer, sans rien modifier
terraform apply      # affiche le plan, demande "yes", puis exécute
terraform destroy    # supprime toutes les ressources gérées par cette configuration

Le plan est le moment clé. Lisez ses symboles :

Symbole Signification
+ création
~ modification sur place
-/+ destruction puis recréation (remplacement)
- destruction

Il se termine par un résumé du type Plan: 1 to add, 0 to change, 0 to destroy. Un remplacement inattendu (-/+) sur une base de données signifie une perte de données : c’est exactement ce que la lecture du plan doit intercepter. La mention # forces replacement indique quel attribut provoque ce remplacement.

Le fichier .terraform.lock.hcl enregistre les versions exactes des providers : il se versionne dans Git, pour que toute l’équipe et la CI utilisent les mêmes. Le dossier .terraform/ ne se versionne pas.

Le fichier d’état

Après un apply, Terraform écrit terraform.tfstate, un fichier JSON qui associe chaque adresse (aws_s3_bucket.exports) à l’objet réel (son identifiant chez AWS) et à ses attributs. Sans lui, Terraform ne saurait pas que le bucket existe déjà et tenterait de le recréer.

terraform state list                       # adresses gérées
terraform state show aws_s3_bucket.exports # attributs connus d'une ressource

Trois règles :

  1. Ne jamais modifier l’état à la main : utilisez les commandes terraform state ou les blocs moved et import (leçon 5).
  2. Ne jamais le versionner dans Git : il contient souvent des valeurs sensibles (mots de passe générés, clés) en clair.
  3. Ne jamais le perdre : c’est la mémoire de votre infrastructure.

Un backend distant verrouillé

Sur un poste seul, l’état est un fichier local. En équipe, on le place dans un backend distant partagé, chiffré et versionné, avec un verrou : si Alice lance un apply, Bruno ne peut pas en lancer un second en même temps et corrompre l’état.

terraform {
  backend "s3" {
    bucket       = "atelier-nova-tfstate"
    key          = "plateforme/prod/terraform.tfstate"
    region       = "eu-west-3"
    encrypt      = true
    use_lockfile = true   # verrou natif dans S3 (versions récentes de Terraform)
  }
}

Les anciennes configurations utilisent une table DynamoDB pour le verrou (dynamodb_table) ; le backend gcs de Google Cloud verrouille nativement. Le bucket d’état lui-même est créé une fois, à part (souvent par une petite configuration dédiée), avec le versionnage activé pour pouvoir restaurer un état précédent. Après avoir ajouté ou changé un backend, relancez terraform init : Terraform propose de migrer l’état existant.

Exercices

Les solutions et les tests restent sur le serveur. Dans l'espace étudiant, ton code est exécuté et corrigé, et le tuteur donne des indices avant la solution.

  1. TâcheDifficulté 12 indices

    Premier cycle complet avec le provider local

    Dans un dossier vide tf-intro, créez main.tf avec le provider hashicorp/local (version ~> 2.5) et une ressource local_file nommée hello, de chemin ${path.module}/hello.txt et de contenu "Bonjour Terraform\n". Lancez terraform init, terraform plan, terraform apply (répondez yes), puis cat hello.txt et terraform state list.

    • `terraform init` se termine par « Terraform has been successfully initialized! » et crée `.terraform.lock.hcl`
    • Le plan affiche la ligne exacte `Plan: 1 to add, 0 to change, 0 to destroy.`
    • `cat hello.txt` affiche `Bonjour Terraform`
    • `terraform state list` affiche exactement `local_file.hello`
    • Un fichier `terraform.tfstate` est apparu dans le dossier
  2. TâcheDifficulté 22 indices

    Lire un remplacement puis tout détruire

    Dans tf-intro, remplacez le contenu de local_file.hello par "Bonjour Terraform, version 2\n". Lancez terraform plan et repérez le symbole utilisé, puis appliquez. Enfin lancez terraform destroy et confirmez.

    • Le plan marque `local_file.hello` avec `-/+` et la mention `# forces replacement` sur `content`
    • Le résumé du plan est exactement `Plan: 1 to add, 0 to change, 1 to destroy.`
    • Après apply, `cat hello.txt` affiche `Bonjour Terraform, version 2`
    • `terraform destroy` se termine par `Destroy complete! Resources: 1 destroyed.` et hello.txt n'existe plus
    • `terraform state list` n'affiche plus rien
  3. QCMDifficulté 11 indice

    Que versionner dans Git ?

    Parmi ces éléments d’un projet Terraform, lequel doit être versionné dans Git ?

    • Le dossier `.terraform/`
    • Le fichier `terraform.tfstate`
    • Le fichier `.terraform.lock.hcl`
    • Le fichier `terraform.tfstate.backup`

Quiz de fin de leçon

  1. Que fait terraform plan ?

    • Il crée les ressources
    • Il calcule et affiche les actions nécessaires sans rien modifier
    • Il télécharge les providers
  2. Que signifie le symbole -/+ dans un plan ?

    • Modification sur place
    • Destruction puis recréation de la ressource
    • Ressource ignorée
  3. Pourquoi verrouiller l’état dans un backend distant ?

    • Pour le rendre plus rapide
    • Pour empêcher deux apply simultanés de corrompre l'état
    • Pour le chiffrer automatiquement dans Git

La suite du cours

  1. Variables, outputs, locals et boucles18 min
  2. Modules : réutiliser et composer18 min
  3. Gérer plusieurs environnements16 min
  4. Revue de plan, CI et évolution de l'existant20 min

Infrastructure as code avec Terraform · Avancé · 1 h 30