Terraform
Infrastructure décrite en fichiers, appliquée de façon idempotente. On décrit l'état voulu, Terraform calcule les opérations pour y arriver.
Le cycle
terraform init # télécharge les providers, configure le backend
terraform fmt # reformate le HCL
terraform validate # vérifie la syntaxe et les références
terraform plan # ce qui va changer, sans rien faire
terraform apply # applique après confirmation
terraform destroy # supprime tout ce qui est géré
terraform plan
Terraform will perform the following actions:
# aws_s3_bucket.artifacts will be created
+ resource "aws_s3_bucket" "artifacts" {
+ bucket = "monprojet-artifacts"
+ id = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Toujours lire le plan avant d'appliquer. La ligne à surveiller est le nombre de
destroy : un changement anodin peut provoquer un remplacement de ressource.
Structure d'un projet
main.tf ressources
variables.tf entrées
outputs.tf sorties
providers.tf providers et versions
terraform.tfvars valeurs (à ne pas committer si secrets)
terraform {
required_version = ">= 1.9"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0" # >= 5.0, < 6.0
}
}
backend "s3" {
bucket = "mon-tfstate"
key = "prod/terraform.tfstate"
region = "eu-west-3"
}
}
provider "aws" {
region = var.region
}
Le backend distant est le premier réflexe en équipe : sans lui, le fichier d'état vit sur un poste et deux personnes qui appliquent en même temps se marchent dessus.
Variables et sorties
variable "region" {
type = string
default = "eu-west-3"
description = "Région AWS"
}
variable "instance_count" {
type = number
validation {
condition = var.instance_count > 0
error_message = "Il faut au moins une instance."
}
}
output "bucket_url" {
value = aws_s3_bucket.artifacts.bucket_domain_name
}
output "db_password" {
value = random_password.db.result
sensitive = true # masqué dans les logs
}
terraform apply -var="region=eu-west-1"
terraform apply -var-file="prod.tfvars"
TF_VAR_region=eu-west-1 terraform apply
Ressources et références
resource "aws_s3_bucket" "artifacts" {
bucket = "${var.project}-artifacts"
tags = {
Environment = var.env
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_versioning" "artifacts" {
bucket = aws_s3_bucket.artifacts.id # crée la dépendance implicite
versioning_configuration {
status = "Enabled"
}
}
Le graphe de dépendances se déduit des références. depends_on ne sert que pour les
dépendances invisibles.
Boucles et conditions
resource "aws_instance" "worker" {
count = var.instance_count
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
tags = { Name = "worker-${count.index}" }
}
resource "aws_s3_bucket" "per_env" {
for_each = toset(["dev", "staging", "prod"])
bucket = "monprojet-${each.key}"
}
locals {
is_prod = var.env == "prod"
size = local.is_prod ? "t3.large" : "t3.micro"
}
Préférer for_each à count : avec count, supprimer un élément au milieu décale les
index et Terraform détruit puis recrée tout ce qui suit.
Data sources
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"]
}
}
État
terraform state list
terraform state show aws_s3_bucket.artifacts
terraform import aws_s3_bucket.artifacts mon-bucket-existant
terraform state rm aws_s3_bucket.artifacts # oublie sans détruire
terraform refresh
import sert à reprendre la main sur une ressource créée à la main dans la console.
Modules
module "network" {
source = "./modules/network"
cidr = "10.0.0.0/16"
}
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.8.1"
name = "prod"
}
# module.network.subnet_ids pour lire une sortie
Cibler et forcer
terraform plan -target=aws_s3_bucket.artifacts # dépannage, pas une habitude
terraform apply -replace=aws_instance.worker[0] # recrée une ressource
terraform apply -auto-approve # CI uniquement
Pièges
Le .tfstate contient des secrets en clair : jamais dans git, toujours dans un backend
chiffré. Un terraform destroy sur le mauvais workspace est irréversible. Et le plan
n'est valide qu'à l'instant où il est produit — si quelqu'un modifie l'infra à la main
entre-temps, l'apply diverge.