Aller au contenu

Terragrunt

Bonne question de base — c'est important de bien fixer ce concept avant d'aller plus loin.

Définition

Un module Terraform est simplement un ensemble de fichiers de configuration Terraform regroupés dans un répertoire qui décrit une unité logique d'infrastructure réutilisable.

Autrement dit : tout répertoire contenant des fichiers .tf est un module Terraform. Il n'y a pas de notion de "module" à activer ou de syntaxe spéciale — c'est juste une convention de regroupement.

Les deux types de modules

1. Le module racine (root module)

C'est le répertoire depuis lequel vous lancez terraform apply. Il contient :

  • Votre fichier main.tf avec les ressources
  • Un variables.tf (optionnel)
  • Un outputs.tf (optionnel)
  • Un terraform.tfstate (l'état)

Exemple minimal :

mon-projet/
├── main.tf
├── variables.tf
└── outputs.tf

Vous lancez terraform apply ici → ce répertoire est le module racine.

2. Les modules enfants (child modules)

Ce sont des modules appelés depuis un autre module via un bloc module. Ils sont généralement stockés dans un sous-répertoire modules/ ou dans un registre distant.

mon-projet/
├── main.tf              # module racine
├── variables.tf
└── modules/
    ├── vpc/             # module enfant
    │   ├── main.tf
    │   ├── variables.tf
    │   └── outputs.tf
    └── s3-bucket/       # module enfant
        ├── main.tf
        ├── variables.tf
        └── outputs.tf

Comment on utilise un module

Trois éléments suffisent à comprendre :

1. Le module expose des variables d'entrée (variables.tf) :

variable "bucket_name" {
  type = string
}

variable "environment" {
  type = string
}

2. Le module expose des sorties (outputs.tf) :

output "bucket_arn" {
  value = aws_s3_bucket.this.arn
}

3. On l'appelle depuis un autre module :

module "mon_bucket" {
  source = "./modules/s3-bucket"

  bucket_name = "my-bucket-dev"
  environment = "dev"
}

Le bloc module est l'équivalent d'un appel de fonction : - source = où trouver le module - les arguments = les paramètres d'entrée - module.mon_bucket.bucket_arn = la valeur de retour

Pourquoi c'est central dans Terraform

Le module répond à trois besoins :

  1. Réutilisabilité : on écrit la logique d'un bucket S3 une fois, on l'instancie 10 fois avec des paramètres différents
  2. Encapsulation : l'appelant n'a pas besoin de savoir comment le bucket est créé, juste quels inputs/outputs existent
  3. Composition : un module peut en appeler d'autres, formant une arborescence

C'est exactement pour ça que la structure Terragrunt vue plus haut sépare modules/ (le code réutilisable) de live/ (les instanciations par environnement). Le terragrunt.hcl ne fait que piloter l'instanciation d'un module Terraform :

terraform {
  source = "../../../modules/s3-bucket"
}

inputs = {
  bucket_name = "my-project-dev-bucket"
  environment = "dev"
}

Analogie rapide

Concept Analogie programmation
Module Terraform Fonction / classe
variables.tf Paramètres d'entrée
outputs.tf Valeur de retour
Bloc module Appel de fonction
source Chemin d'import
Module racine Le main()

Sources de modules

Un module peut venir de plusieurs endroits :

# Répertoire local
source = "./modules/vpc"

# Registre Terraform public
source = "terraform-aws-modules/vpc/aws"

# Dépôt Git
source = "git::https://github.com/org/repo.git//modules/vpc?ref=v1.2.0"

# Bucket S3
source = "s3::https://s3-eu-west-3.amazonaws.com/mon-bucket/vpc.zip"

C'est ce mécanisme de source que Terragrunt utilise dans son bloc terraform { source = ... }.

Ce qu'il faut retenir

  • Un module = un répertoire de fichiers .tf
  • Le module racine est celui où vous lancez les commandes
  • Les modules enfants sont appelés via module { source = ... }
  • Un module expose des variables (entrée) et des outputs (sortie)
  • Terraform seul gère les modules, mais vous devez instancier chaque module manuellement dans chaque environnement — c'est précisément la douleur que Terragrunt vient résoudre