Terraform en pratique : gérer votre infrastructure AWS comme du code
Par Lenine Djouatsa
Pourquoi l’Infrastructure as Code change tout
Avant l’IaC, les infrastructures étaient créées à la main via des consoles web, des scripts bash disparates, ou une documentation qui devenait vite obsolète. Le résultat : des environnements « flocons de neige » impossibles à reproduire, des incidents liés à des configurations manuelles, et une dette technique invisible mais croissante.
Terraform résout ces problèmes en permettant de décrire l’infrastructure souhaitée dans des fichiers .tf versionnés dans Git, avec la même rigueur que votre code applicatif.
Structure d’un projet Terraform professionnel
infrastructure/
├── modules/
│ ├── vpc/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ └── outputs.tf
│ ├── ecs-service/
│ └── rds/
├── environments/
│ ├── staging/
│ │ ├── main.tf
│ │ ├── terraform.tfvars
│ │ └── backend.tf
│ └── production/
│ ├── main.tf
│ ├── terraform.tfvars
│ └── backend.tf
└── .gitlab-ci.yml
La séparation modules / environments permet de réutiliser les patterns d’infrastructure sans duplication de code.
Le State : le cœur de Terraform
Le fichier terraform.tfstate est la mémoire de Terraform : il mappe vos ressources déclarées aux ressources réelles dans AWS. En équipe, ce fichier doit impérativement être stocké à distance :
# environments/production/backend.tf
terraform {
backend "s3" {
bucket = "mon-terraform-state"
key = "production/terraform.tfstate"
region = "eu-west-3"
encrypt = true
dynamodb_table = "terraform-state-lock"
}
}
DynamoDB est utilisé pour le verrouillage du state, essentiel pour éviter deux apply simultanés qui corrompraient l’état.
Exemple concret : déployer un cluster ECS Fargate
# modules/ecs-service/main.tf
resource "aws_ecs_cluster" "main" {
name = "${var.project}-${var.env}"
setting {
name = "containerInsights"
value = "enabled"
}
}
resource "aws_ecs_task_definition" "app" {
family = "${var.project}-app"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = var.task_cpu
memory = var.task_memory
execution_role_arn = aws_iam_role.ecs_execution.arn
container_definitions = jsonencode([{
name = "app"
image = "${var.ecr_repository_url}:${var.image_tag}"
portMappings = [{ containerPort = 4321 }]
environment = [
{ name = "NODE_ENV", value = "production" }
]
logConfiguration = {
logDriver = "awslogs"
options = {
"awslogs-group" = "/ecs/${var.project}"
"awslogs-region" = var.aws_region
"awslogs-stream-prefix" = "app"
}
}
}])
}
Pipeline GitLab CI pour Terraform
.terraform:base:
image: hashicorp/terraform:1.7
before_script:
- cd environments/$ENVIRONMENT
- terraform init -backend-config="access_key=$AWS_ACCESS_KEY_ID"
terraform:plan:
extends: .terraform:base
script:
- terraform plan -out=tfplan
artifacts:
paths: [environments/$ENVIRONMENT/tfplan]
terraform:apply:
extends: .terraform:base
script:
- terraform apply tfplan
when: manual
environment:
name: $ENVIRONMENT
La règle when: manual sur l’apply garantit qu’un humain valide chaque modification de l’infrastructure de production.
Les 5 règles d’or de l’IaC avec Terraform
- Ne jamais modifier l’infrastructure manuellement après adoption de Terraform (le state divergerait)
- Toujours committer le plan avant l’apply pour visualiser ce qui va changer
- Utiliser des modules versionnés :
source = "git::https://...//modules/vpc?ref=v2.1.0" - Vérouiller les versions des providers :
required_providersavec contrainte~>stricte - Tagger toutes les ressources : crucial pour le contrôle des coûts et la gouvernance
Conclusion
Terraform transforme l’infrastructure en actif versionnable, auditable et reproductible. La courbe d’apprentissage est réelle mais l’investissement se rentabilise dès le premier incident évité grâce à un environnement recréable en minutes.
Chez aCloud.Digital, nous formons les équipes à Terraform et Ansible dans le cadre de notre Formation DevOps. N’hésitez pas à nous contacter pour un accompagnement personnalisé.