Workflow de base
terraform init → terraform plan → terraform apply → terraform destroy
$terraform init
Initialise le backend, télécharge les providers et modules
$terraform plan
Affiche les changements prévus sans les appliquer
$terraform apply
Applique les changements (demande confirmation)
$terraform apply -auto-approve
Applique sans demander confirmation (CI/CD)
$terraform destroy
Supprime toutes les ressources gérées
Structure de projet
infra/
├── main.tf # Ressources principales
├── variables.tf # Déclaration des variables
├── outputs.tf # Valeurs de sortie
├── providers.tf # Configuration des providers
├── terraform.tfvars # Valeurs des variables (non commit)
├── backend.tf # Configuration du state backend
└── modules/
├── vpc/
├── eks/
└── rds/
Ressources
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.micro"
tags = {
Name = "web-server"
Environment = "production"
}
}Variables
# variables.tf
variable "region" {
description = "AWS region"
type = string
default = "eu-west-3"
}
variable "instance_count" {
description = "Number of instances"
type = number
default = 2
}
variable "allowed_cidrs" {
description = "Allowed CIDR blocks"
type = list(string)
default = ["10.0.0.0/8"]
}
variable "tags" {
description = "Resource tags"
type = map(string)
default = {}
}# terraform.tfvars
region = "eu-west-3"
instance_count = 3
allowed_cidrs = ["10.0.0.0/8", "172.16.0.0/12"]Outputs
output "instance_ip" {
description = "Public IP of the web server"
value = aws_instance.web.public_ip
}
output "db_endpoint" {
description = "RDS endpoint"
value = aws_db_instance.main.endpoint
sensitive = true
}$terraform output
$terraform output -json
State
$terraform state list
Liste toutes les ressources dans le state
$terraform state show aws_instance.web
Details d'une ressource
$terraform state mv aws_instance.web aws_instance.api
Renommer une ressource dans le state
$terraform import aws_instance.web i-1234567890abcdef0
Importer une ressource existante
Backend S3 (recommandé)
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "eu-west-3"
dynamodb_table = "terraform-locks"
encrypt = true
}
}Modules
module "vpc" {
source = "./modules/vpc"
cidr_block = "10.0.0.0/16"
environment = "production"
project_name = "mon-app"
}
# Utiliser un module du registry
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "~> 20.0"
cluster_name = "mon-cluster"
cluster_version = "1.31"
}Expressions utiles
# Boucle for_each
resource "aws_subnet" "private" {
for_each = toset(["a", "b", "c"])
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(aws_vpc.main.cidr_block, 8, index(["a", "b", "c"], each.key))
availability_zone = "${var.region}${each.key}"
}
# Condition
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? 1 : 0
}
# Data source
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.04-amd64-server-*"]
}
}Bonnes pratiques
- Remote state : S3 + DynamoDB pour le locking
- Modules : réutiliser et versionner l'infrastructure
- Workspaces : séparer dev/staging/prod
- Plan avant apply : toujours reviewer le plan
- Versionner les providers : pinning avec
~>ou= - tfvars secrets : ne jamais commiter, utiliser des variables d'environnement ou un vault