Aller au contenu
Infrastructure as Code medium

Terragrunt : stacks implicites ou explicites ?

11 min de lecture

logo terragrunt

Vous avez vu des mentions de stacks dans Terragrunt, mais vous ne savez pas si vous devez utiliser l'approche implicite ou explicite ? La réponse dépend de la taille de votre repo et de votre besoin de réutilisation.

Cette page compare les deux approches sur un même module minimal, avec un lab que vous pouvez rejouer, pour choisir en connaissance de cause.

  • Comprendre la différence entre stack implicite et stack explicite
  • Reproduire les deux approches sur un même module minimal
  • Choisir le bon point de départ selon la taille de votre repo
  • Savoir quand passer de l'une à l'autre

Avant le détail, voici la règle de décision. Ne cherchez pas la stack la plus sophistiquée : cherchez celle qui reste lisible pour la forme actuelle de votre repo. Le critère qui tranche est la réutilisation : tant que vos units vivent naturellement dans des dossiers distincts, l'implicite suffit ; dès que vous voulez générer plusieurs fois la même composition avec des valeurs différentes, l'explicite prend l'avantage.

Votre besoinPoint de départ recommandé
Quelques units rangées naturellement par dossiersStack implicite
Une composition réutilisable de plusieurs unitsStack explicite
Un repo encore débutant, peu de répétitionStack implicite
Un modèle à générer plusieurs fois avec des valeurs différentesStack explicite

Pour comparer les deux approches sans bruit, on réutilise exactement le même module Terraform ou OpenTofu dans les deux cas. Placez-le dans modules/write-file/main.tf :

terraform {
required_version = ">= 1.6.0"
required_providers {
local = {
source = "hashicorp/local"
version = "~> 2.5"
}
}
}
variable "filename" {
type = string
}
variable "content" {
type = string
}
resource "local_file" "this" {
filename = var.filename
content = var.content
}
output "file_path" {
value = local_file.this.filename
}
output "content" {
value = local_file.this.content
}

Le résultat observé est simple : chaque unit crée un fichier local avec un nom et un contenu différents. C'est volontaire : en réduisant le module à l'essentiel, la seule chose qui change entre les deux labs est la façon de composer les units, pas le code Terraform.

Dans une stack implicite, c'est l'arborescence qui raconte la composition. Terragrunt parcourt les dossiers déployables et construit sa logique à partir de la structure et, si besoin, des dépendances déclarées.

Regardez d'abord la séparation des rôles dans cette arborescence : le dossier modules/ porte le code Terraform réutilisable, tandis que live/ décrit ce qui est réellement déployé. Le fichier root.hcl ancre la racine du repo Terragrunt, _env/ factorise la configuration commune, et chaque sous-dossier de dev/ (foo, bar) est une unit distincte. Aucun fichier ne liste les units : leur simple présence dans l'arborescence suffit.

  • Répertoirelab-implicit/
    • Répertoiremodules/
      • Répertoirewrite-file/
        • main.tf
    • Répertoirelive/
      • root.hcl
      • Répertoire_env/
        • write-file.hcl
      • Répertoiredev/
        • Répertoirefoo/
          • terragrunt.hcl
        • Répertoirebar/
          • terragrunt.hcl

Chaque fichier ci-dessous a un rôle précis, du plus général au plus spécifique. Le root.hcl définit ce qui vaut pour tout le repo, le _env/write-file.hcl factorise la source du module et un input commun, et les deux terragrunt.hcl d'unit ne portent plus que ce qui leur est propre, leur nom de fichier et leur contenu. C'est cette cascade d'include qui évite de répéter la source du module dans chaque unit.

Fichier live/root.hcl :

locals {
stack_name = "dev"
}

Fichier live/_env/write-file.hcl :

locals {
module_source = "${dirname(find_in_parent_folders("root.hcl"))}/../modules/write-file"
}
inputs = {
content_prefix = "hello"
}

Fichier live/dev/foo/terragrunt.hcl :

include "root" {
path = find_in_parent_folders("root.hcl")
expose = true
}
include "env" {
path = "${get_terragrunt_dir()}/../../_env/write-file.hcl"
expose = true
}
terraform {
source = include.env.locals.module_source
}
inputs = {
filename = "${get_terragrunt_dir()}/foo.txt"
content = "${include.env.inputs.content_prefix} from foo in ${include.root.locals.stack_name}"
}

Fichier live/dev/bar/terragrunt.hcl :

include "root" {
path = find_in_parent_folders("root.hcl")
expose = true
}
include "env" {
path = "${get_terragrunt_dir()}/../../_env/write-file.hcl"
expose = true
}
terraform {
source = include.env.locals.module_source
}
inputs = {
filename = "${get_terragrunt_dir()}/bar.txt"
content = "${include.env.inputs.content_prefix} from bar in ${include.root.locals.stack_name}"
}
  1. Créer les fichiers du live repo

    Vérification : vous avez bien root.hcl, _env/write-file.hcl, puis deux units foo et bar.

  2. Vous placer dans live/dev

    Puis lancer :

    Fenêtre de terminal
    terragrunt run --all apply

    Vérification : foo/foo.txt contient hello from foo in dev et bar/bar.txt contient hello from bar in dev.

  3. Nettoyer

    Fenêtre de terminal
    terragrunt run --all destroy

    Vérification : les deux fichiers ont disparu.

Dans une stack explicite, vous ne laissez plus uniquement l'arborescence porter la composition. Vous déclarez la liste des units dans un fichier terragrunt.stack.hcl.

La différence se voit tout de suite dans l'arborescence : il n'existe plus de dossier foo ou bar écrit à la main. Une seule unit générique vit dans units/write-file-unit/, et le fichier terragrunt.stack.hcl de stacks/dev/ décrit combien de fois l'instancier et avec quelles valeurs. Les dossiers déployables seront générés par Terragrunt, ils n'existent pas avant la commande de génération.

  • Répertoirelab-explicit/
    • Répertoiremodules/
      • Répertoirewrite-file/
        • main.tf
    • Répertoirestacks/
      • Répertoiredev/
        • terragrunt.stack.hcl
    • Répertoireunits/
      • Répertoirewrite-file-unit/
        • terragrunt.hcl

Deux fichiers seulement, avec un partage clair. L'unit write-file-unit/terragrunt.hcl est un gabarit : il ne connaît pas ses valeurs finales, il les lit dans values.filename et values.content, injectées à la génération. Le fichier terragrunt.stack.hcl est la source de vérité de la composition : chaque bloc unit fixe un path de sortie et le bloc values qui alimente le gabarit. C'est ce couplage gabarit plus valeurs qui permet de rejouer la même unit autant de fois que voulu.

Fichier units/write-file-unit/terragrunt.hcl :

terraform {
source = "../../modules/write-file"
}
inputs = {
filename = "${get_terragrunt_dir()}/${values.filename}"
content = values.content
}

Fichier stacks/dev/terragrunt.stack.hcl :

unit "app" {
source = "../../units/write-file-unit"
path = "app"
no_dot_terragrunt_stack = true
values = {
filename = "stack-app.txt"
content = "hello from explicit stack app"
}
}
unit "worker" {
source = "../../units/write-file-unit"
path = "worker"
no_dot_terragrunt_stack = true
values = {
filename = "stack-worker.txt"
content = "hello from explicit stack worker"
}
}
  1. Vous placer dans stacks/dev

    Puis lancer :

    Fenêtre de terminal
    terragrunt stack generate

    Vérification : deux dossiers app et worker apparaissent avec leurs fichiers terragrunt.hcl.

  2. Appliquer la stack

    Fenêtre de terminal
    terragrunt run --all apply

    Vérification : app/stack-app.txt contient hello from explicit stack app et worker/stack-worker.txt contient hello from explicit stack worker.

  3. Nettoyer

    Fenêtre de terminal
    terragrunt run --all destroy

    Vérification : les deux fichiers ont disparu.

Une fois les deux labs rejoués, la distinction se résume à une question : où vit la composition ? En implicite, elle est éclatée dans l'arborescence, ce qui reste très lisible tant que le repo est petit. En explicite, elle est concentrée dans un fichier terragrunt.stack.hcl, ce qui permet de la générer et de la rejouer, au prix d'un niveau d'indirection en plus. Le tableau résume les points de bascule.

AspectStack impliciteStack explicite
Source de véritéL'arborescence du repoLe fichier terragrunt.stack.hcl
Mise en routePlus simple au débutPlus structurée
Génération de unitsManuelleAutomatique via stack generate
Lisibilité sur petit repoExcellenteParfois excessive
Réutilisation d'une compositionLimitéePlus forte
  • Choisissez la stack implicite si votre repo reste lisible naturellement par dossiers et que vous voulez avancer sans sur-architecture.
  • Choisissez la stack explicite si vous voulez décrire, générer et rejouer plusieurs units comme un bloc cohérent et réutilisable.

La plupart des blocages sur les stacks viennent d'une structure choisie trop tôt, pas d'un bug de l'outil. Une stack explicite posée sur un repo encore minuscule ajoute de l'indirection sans bénéfice ; à l'inverse, un repo implicite qui a trop grossi finit par disperser sa logique dans les dossiers. Lisez la colonne cause probable avant la solution : dans deux cas sur trois, la correction consiste à revenir à l'approche plus simple.

SymptômeCause probableSolution
Le repo implicite devient confusTrop de logique est dispersée dans les dossiersRevenir à root.hcl, _env et des units plus lisibles
stack generate ne crée rienMauvais source ou mauvais cheminVérifier terragrunt.stack.hcl et le dossier courant
Une stack explicite semble trop lourdeLe repo est encore trop simpleRevenir à une stack implicite
  • Une stack implicite s'appuie surtout sur l'arborescence du repo.
  • Une stack explicite décrit la composition dans terragrunt.stack.hcl.
  • Les deux approches peuvent réutiliser exactement le même module.
  • Commencez simple, puis montez en explicite quand la composition devient un vrai sujet.
  • Le bon choix dépend moins de l'outil que de la taille et de la forme du repo.

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