Config root, config account, config environment. Une valeur, définie une fois, dispo partout. Zéro copier-coller.
J’avais 12 dossiers d’environnements. Même région AWS partout. Mêmes tags. Même config KMS
Je change la région? Je dois toucher 12 fichiers. J’ajoute un tag? Encore 12 fichiers. J’en rate un? Cet environnement explose différemment des autres
Terragrunt règle ça avec son système de hiérarchie. Tu définis chaque valeur une fois au bon endroit, elle descend automatiquement partout
Hiérarchie logique
Tes valeurs d’infra, elles rentrent dans des catégories. Y’en a qui valent pour tout. D’autres juste pour un compte AWS. D’autres pour un environnement. D’autres pour une région
root.hcl → Tout: backend, provider, tags projet
account.hcl → Compte AWS: ID, rôles IAM, centre de coût
environment.hcl → Environnement: prod vs staging, domaines
region.hcl → Région: zones dispo, endpoints Chaque niveau hérite du dessus. Ton module database dans prod/us-east-1/database/, il récupère automatiquement les quatre niveaux
Zéro duplication. Zéro copier-coller. Une source de vérité par valeur
Config root: ce qui vaut partout
root.hcl à la racine de ton infra. Il contient ce que toutes tes ressources partagent:
# infrastructure/root.hcl
locals {
project_name = "myapp"
project_id = "app123"
# Ces tags vont sur tout
root_tags = {
"project" = "myapp"
"managed-by" = "terraform"
"cost-center" = "engineering"
}
}
# Charge les configs enfants
locals {
account_vars = read_terragrunt_config(find_in_parent_folders("account.hcl"))
environment_vars = read_terragrunt_config(find_in_parent_folders("environment.hcl"))
region_vars = read_terragrunt_config(find_in_parent_folders("region.hcl"))
}
# Backend unique pour tous les modules
remote_state {
backend = "s3"
config = {
bucket = "myapp-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# Provider généré partout
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<-EOF
provider "aws" {
region = "${local.region_vars.locals.region}"
assume_role {
role_arn = "${local.account_vars.locals.iam_role}"
}
default_tags {
tags = var.default_tags
}
}
EOF
}
# Tout dispo en inputs
inputs = merge(
local.account_vars.locals,
local.environment_vars.locals,
local.region_vars.locals,
{
project_name = local.project_name
default_tags = merge(
local.root_tags,
local.account_vars.locals.account_tags,
local.environment_vars.locals.environment_tags
)
}
) T’écris ton backend une fois. Ton provider une fois. Tes tags root une fois
Tous tes modules récupèrent ça automatiquement. Besoin de changer le bucket S3? Une ligne. Un tag? Une ligne
Config account: le niveau compte AWS
account.hcl contient ce qui est propre à un compte AWS. T’as des comptes séparés prod/non-prod? Un fichier par compte:
# infrastructure/prod-account/account.hcl
locals {
account_id = "123456789012"
account_name = "production"
# Rôle IAM pour les déploiements
iam_role = "arn:aws:iam::123456789012:role/terraform-deploy"
# Tags de coûts niveau compte
account_tags = {
"environment" = "production"
"account-id" = "123456789012"
"criticality" = "high"
}
# Config prod
enable_deletion_protection = true
backup_retention_days = 90
} # infrastructure/staging-account/account.hcl
locals {
account_id = "987654321098"
account_name = "staging"
iam_role = "arn:aws:iam::987654321098:role/terraform-deploy"
account_tags = {
"environment" = "staging"
"account-id" = "987654321098"
"criticality" = "medium"
}
enable_deletion_protection = false
backup_retention_days = 30
} L’ID du compte, le rôle IAM, les policies: c’est défini une fois. Chaque ressource du compte les récupère
Besoin de changer le rôle IAM prod? Un fichier. Ajouter des tags compte? Un fichier
Config environment: prod vs staging
environment.hcl contient les différences entre prod et staging dans le même compte:
# infrastructure/prod-account/prod/environment.hcl
locals {
environment = "prod"
environment_tags = {
"environment" = "prod"
}
# Domaine prod
domain_name = "myapp.com"
# Sizing prod
database_instance_class = "db.r6g.xlarge"
cache_node_type = "cache.r6g.large"
# Scaling prod
min_instances = 3
max_instances = 10
# Monitoring prod
enable_detailed_monitoring = true
alarm_email = "oncall@company.com"
} # infrastructure/prod-account/staging/environment.hcl
locals {
environment = "staging"
environment_tags = {
"environment" = "staging"
}
domain_name = "staging.myapp.com"
# Staging plus petit
database_instance_class = "db.t4g.medium"
cache_node_type = "cache.t4g.small"
min_instances = 1
max_instances = 3
enable_detailed_monitoring = false
alarm_email = "dev-team@company.com"
} Les différences prod/staging sont explicites. Tailles d’instances, domaines, scaling
Tes ressources prod ont les valeurs prod. Tes ressources staging ont les valeurs staging. Impossible de mélanger
Config region: le géographique
region.hcl contient ce qui change par région:
# infrastructure/prod-account/prod/us-east-1/region.hcl
locals {
region = "us-east-1"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
# Endpoints régionaux
regional_domain = "use1.myapp.com"
} # infrastructure/prod-account/prod/eu-west-1/region.hcl
locals {
region = "eu-west-1"
availability_zones = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
regional_domain = "euw1.myapp.com"
} T’as un fichier par région. Tu veux déployer dans une nouvelle région? Tu dupliques le dossier et tu modifies juste region.hcl
Le reste descend d’en haut. Les configs account, environment, root s’appliquent automatiquement
Config module: le niveau détail
En bas de la pile, chaque module a son terragrunt.hcl:
# infrastructure/prod-account/prod/us-east-1/database/terragrunt.hcl
include "root" {
path = find_in_parent_folders("root.hcl")
}
terraform {
source = "${get_repo_root()}/modules/database"
}
dependency "network" {
config_path = "../network"
}
inputs = {
# Juste le spécifique au module
db_name = "myapp_prod"
multi_az = true
# Le reste vient de la hiérarchie:
# - region depuis region.hcl
# - database_instance_class depuis environment.hcl
# - backup_retention_days depuis account.hcl
# - default_tags depuis root.hcl
vpc_id = dependency.network.outputs.vpc_id
subnet_ids = dependency.network.outputs.database_subnet_ids
} La config du module est minuscule. Y’a que ce qui est unique à cette base
Le reste? Déjà défini au-dessus. La hiérarchie le fournit
Comment ça descend
Tu lances terragrunt apply dans prod-account/prod/us-east-1/database/:
- Terragrunt trouve
root.hcl, charge la config projet - Charge
account.hclpour les valeurs compte - Charge
environment.hclpour les différences prod/staging - Charge
region.hclpour les paramètres région - Merge tout dans
inputs
Ton module database reçoit:
project_namedepuis rootaccount_id,iam_role,backup_retention_daysdepuis accountenvironment,database_instance_classdepuis environmentregion,availability_zonesdepuis regiondb_name,multi_azdepuis le module
Une variable, une fois, au bon endroit. Zéro duplication
Stratégie de merge
Le bloc inputs dans root.hcl merge tout:
inputs = merge(
local.account_vars.locals,
local.environment_vars.locals,
local.region_vars.locals,
{
project_name = local.project_name
default_tags = merge(
local.root_tags,
local.account_vars.locals.account_tags,
local.environment_vars.locals.environment_tags
)
}
) Les tags sont mergés. Tags account écrasent tags root. Tags environment écrasent tags account
Tu veux des tags globaux? Mets ça dans root. Tags compte? Dans account. Tags environnement? Dans environment
Structure dossiers
infrastructure/
├── root.hcl
├── modules/
│ ├── database/
│ ├── cache/
│ └── app/
├── prod-account/
│ ├── account.hcl
│ ├── prod/
│ │ ├── environment.hcl
│ │ ├── us-east-1/
│ │ │ ├── region.hcl
│ │ │ ├── database/
│ │ │ │ └── terragrunt.hcl
│ │ │ ├── cache/
│ │ │ │ └── terragrunt.hcl
│ │ │ └── app/
│ │ │ └── terragrunt.hcl
│ │ └── eu-west-1/
│ │ ├── region.hcl
│ │ ├── database/
│ │ └── ...
│ └── staging/
│ ├── environment.hcl
│ └── us-east-1/
│ └── ...
└── staging-account/
├── account.hcl
└── ... L’hiérarchie est évidente. Tu sais où chercher. Config compte? account.hcl. Config prod? environment.hcl
Fini de fouiller 47 fichiers pour trouver où est définie une valeur
Configs partagées entre modules
Plusieurs modules partagent la même config? Crée _envcommon/:
# infrastructure/_envcommon/database.hcl
terraform {
source = "${get_repo_root()}/modules/database"
}
locals {
# Charge environment pour trouver les dépendances réseau
environment_vars = read_terragrunt_config(
find_in_parent_folders("environment.hcl")
)
}
dependency "network" {
config_path = "../network"
}
inputs = {
vpc_id = dependency.network.outputs.vpc_id
subnet_ids = dependency.network.outputs.database_subnet_ids
} Chaque instance database l’inclut:
# prod-account/prod/us-east-1/database/terragrunt.hcl
include "root" {
path = find_in_parent_folders("root.hcl")
}
include "envcommon" {
path = "${dirname(find_in_parent_folders("root.hcl"))}/_envcommon/database.hcl"
}
inputs = {
db_name = "myapp_prod"
multi_az = true
} La config commune est partagée. La config spécifique reste locale. Zéro duplication
Exemple concret: nouvelle région
Tu veux déployer dans eu-west-1. Tu dupliques le dossier:
cp -r prod-account/prod/us-east-1 prod-account/prod/eu-west-1 Tu modifies un seul fichier:
# prod-account/prod/eu-west-1/region.hcl
locals {
region = "eu-west-1"
availability_zones = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
} Tu lances:
cd prod-account/prod/eu-west-1
terragrunt run-all apply Chaque module dans cette région récupère:
- La nouvelle région automatiquement
- La config account inchangée
- La config environment inchangée
- La config root inchangée
T’as changé une valeur. Tout le reste descend automatiquement
Ce que ça résout
Avant la hiérarchie Terragrunt:
- Région AWS dans 12 endroits
- Config backend dupliquée partout
- Tags copiés dans tous les environnements
- Rôles IAM éparpillés
- Aucune idée où mettre quoi
Après:
- Région dans
region.hcl, une fois - Backend dans
root.hcl, une fois - Tags mergés depuis root/account/environment
- Rôle IAM dans
account.hcl, une fois - Hiérarchie claire, évident où va chaque valeur
J’ai changé l’ID de notre compte AWS prod. Un fichier. 10 secondes
Avant ça? J’aurais grep dans 47 fichiers, modifié chacun, raté deux, cassé staging, passé une heure à débugger
Patterns utiles
Dépendances entre environnements: La prod qui utilise le VPC de staging pour le VPN:
# prod-account/prod/environment.hcl
locals {
network_dependency_path = "${get_repo_root()}/infrastructure/staging-account/staging/us-east-1/network"
} Préfixes dynamiques: Générer les noms de ressources depuis la hiérarchie:
# root.hcl
locals {
prefix = "${local.project_id}-${local.environment_vars.locals.environment}-${local.region_vars.locals.region}"
}
inputs = {
resource_prefix = local.prefix
} Tes ressources dans prod/us-east-1 ont le préfixe app123-prod-us-east-1. Celles dans staging/eu-west-1 ont app123-staging-eu-west-1. Zéro conflits
Config conditionnelle: Features actives seulement dans certains environnements:
# prod-account/prod/environment.hcl
locals {
enable_waf = true
enable_enhanced_monitoring = true
}
# staging-account/staging/environment.hcl
locals {
enable_waf = false
enable_enhanced_monitoring = false
} Quand éviter
Petits projets avec un seul environnement. La hiérarchie c’est overkill. Un seul terragrunt.hcl suffit
Infra complètement différente par environnement. Si prod et staging n’ont rien en commun, la hiérarchie t’apporte pas grand chose
Projets où chaque module est unique. Rien à réutiliser? Rien à faire descendre
Démarrer
Pour ajouter la hiérarchie à ton setup Terragrunt:
- Tu déplaces la config backend dans
root.hcl - Tu crées
account.hclavec les valeurs compte - Tu crées
environment.hclavec les valeurs environnement - Tu crées
region.hclavec les valeurs région - Tu modifies
root.hclpour charger et merger tout ça
Commence avec une seule valeur. Déplace la région AWS de tous tes modules vers region.hcl. Vérifie que ça marche
Ensuite les tags. Ensuite les rôles IAM. Une valeur à la fois
Une semaine après t’as une config qui tient la route. Valeurs définies une fois. Hiérarchie claire. Zéro duplication
J’ai passé 6 mois à copier-coller de la config Terraform. J’ai passé 2 jours à setup cette hiérarchie. Je reviens jamais en arrière
Vous avez aimé cet article ?
Faites-le savoir ! Un partage, c'est toujours apprécié.