À la fin de ce tutoriel, vous saurez distinguer EBS et instance store, déclarer un
aws_ebs_volumegp3 chiffré avec tags, comprendreaws_volume_attachment(conceptuel / optionnel), aperçu des snapshots, et exécuter un lab minimal en Regionca-central-1— Terraform ≥ 1.9, AWS provider ~> 5.0. Message clé : volume EBS = ressource indépendante de l’EC2 ; destroy obligatoire ; snapshots = coût.Niveau : Intermédiaire · Temps estimé : 30–40 min · Versions testées : Terraform ≥ 1.9, AWS provider ~> 5.0 · Dernière vérification : 2026-09-10
Slug proposé :
terraform-ebs· Série : Terraform · Remplace / fusionne : #1669 (Volume EBS avec Terraform)
Prérequis
- Avoir suivi Provisioners (
terraform-provisioners) : last resort, cycle apply/destroy - Avoir suivi Workspaces (
terraform-workspaces) et idéalement Variables (terraform-variables) - Terraform ≥ 1.9, AWS CLI v2, profil de lab (
aws sts get-caller-identityOK) - Notions EC2 / AZ utiles (voir maillage VPC et IAM) ; le lab volume ne crée pas d’EC2 obligatoire
Coût estimé : quelques cents maximum pour un gp3 petit (ex. 8–10 Gio) en Free Tier friendly. Les snapshots coûtent en stockage — ne les laissez pas après le lab. Destroy obligatoire en fin de session. Aucun secret dans le HCL / tfvars.
Auth sans secrets. Utilisez
AWS_PROFILE/ SSO. Jamais d’access_key/secret_keydans le provider. Pas de clé KMS CMK hardcodée dans le dépôt : chiffrement AES-256 (clé gérée AWS) suffit pour ce lab.
Ce que nous allons construire
Lab terraform ebs (ca-central-1) — Free Tier friendly
├── versions.tf / providers.tf → TF ≥ 1.9, aws ~> 5.0, region ca-central-1
├── Étapes 1–4 → EBS vs instance store + aws_ebs_volume + attachment + snapshots
├── aws_ebs_volume gp3 petit → encrypted, tags, AZ ca-central-1a
├── (optionnel) aws_volume_attachment → note conceptuelle / data existante
├── destroy obligatoire → volume + snapshots éventuels
└── Checklist + erreurs + quiz
(Alt : « Terraform EBS : volume gp3 chiffré, attachment EC2, snapshots — ca-central-1 ».)
Étape 1 — EBS vs instance store
Avant d’écrire du HCL, clarifiez le stockage EC2 :
| Critère | EBS (Elastic Block Store) | Instance store |
|---|---|---|
| Persistance | Survit au stop / restart (sauf delete_on_termination) | Éphémère — perdu au stop / terminate / failure |
| Portée | Volume lié à une AZ ; attachable à une instance de cette AZ | Disques locaux de l’hôte |
| Cas d’usage | OS data, bases, disques applicatifs | Cache, scratch, workloads tolérants à la perte |
| Terraform | aws_ebs_volume, root via aws_instance / launch template |
Souvent via type d’instance (pas un volume EBS classique) |
| Snapshot | Oui (aws_ebs_snapshot) |
Non (pas de snapshot EBS natif) |
Mot-clé SEO : avec terraform ebs, vous gérez un bloc réseau persistant, pas le stockage temporaire de l’hyperviseur. Pour un lab P2 : gp3 petit, chiffré, tagué, puis destroy.
Étape 2 — aws_ebs_volume (gp3, size, encrypted, tags)
Ressource centrale pour un volume data indépendant :
# versions.tf
terraform {
required_version = ">= 1.9.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
# providers.tf
provider "aws" {
region = "ca-central-1"
# Auth : AWS_PROFILE / SSO — jamais de clés ici
}
# variables.tf
variable "project" {
type = string
description = "Préfixe lab unique (sans secret)."
}
variable "availability_zone" {
type = string
description = "AZ du volume (doit matcher l’instance si attachment)."
default = "ca-central-1a"
}
# main.tf — volume data Free Tier friendly
resource "aws_ebs_volume" "data" {
availability_zone = var.availability_zone
size = 8
type = "gp3"
encrypted = true
# iops / throughput : laisser défauts gp3 pour le lab (coût + simplicité)
tags = {
Name = "${var.project}-ebs-data"
ManagedBy = "terraform"
Lab = "terraform-ebs"
Region = "ca-central-1"
}
}
output "volume_id" {
description = "ID du volume EBS créé."
value = aws_ebs_volume.data.id
}
output "volume_az" {
description = "AZ du volume (critique pour attachment)."
value = aws_ebs_volume.data.availability_zone
}
Points à retenir :
availability_zoneest obligatoire — un volume EBS n’est pas multi-AZ.type = "gp3": défaut moderne ; IOPS/throughput réglables plus tard (hors Free Tier « petit »).encrypted = true: bonne pratique ; sanskms_key_id, AWS utilise la clé gérée du service.sizeen Gio : 8–10 Gio suffit pour apprendre — évitez 100 Gio « par habitude ».- Tags :
Name+Labfacilitent le nettoyage console / Cost Explorer.
Le volume existe sans EC2 : état available jusqu’à un attachment.
Étape 3 — aws_volume_attachment (optionnel / conceptuel)
L’attachment lie un volume à une instance dans la même AZ. Pour ce tuto, l’instance n’est pas créée (coût, SG, AMI). Deux approches pédagogiques :
A. Note conceptuelle (recommandée pour le lab minimal)
# CONCEPTUEL — ne pas appliquer sans instance existante dans la même AZ
# resource "aws_volume_attachment" "data" {
# device_name = "/dev/xvdf"
# volume_id = aws_ebs_volume.data.id
# instance_id = aws_instance.app.id # ou data.aws_instance.existing.id
# }
B. Data source vers une instance déjà running (si vous en avez une de lab dans ca-central-1a) :
# Optionnel : instance préexistante taguée Lab=terraform-ebs-host
data "aws_instance" "existing" {
count = var.attach_existing ? 1 : 0
filter {
name = "tag:Lab"
values = ["terraform-ebs-host"]
}
filter {
name = "instance-state-name"
values = ["running"]
}
}
resource "aws_volume_attachment" "data" {
count = var.attach_existing ? 1 : 0
device_name = "/dev/xvdf"
volume_id = aws_ebs_volume.data.id
instance_id = data.aws_instance.existing[0].id
}
variable "attach_existing" {
type = bool
description = "true seulement si une EC2 lab tourne dans la même AZ."
default = false
}
Règles dures :
- AZ mismatch → erreur API (étape 7).
device_name: convention Linux/dev/xvdf(le guest peut voirnvme…— normal sur Nitro).- Après attachment : formatage / montage = user_data / SSM, pas un provisioner (voir tuto précédent).
- Root volume : souvent géré dans
aws_instance(root_block_device) — hors scope de ce lab « volume data ».
Pour valider le terraform ebs sans EC2 : créez uniquement aws_ebs_volume, vérifiez l’ID en output, puis destroy.
Étape 4 — Snapshots : aperçu et coûts
Un snapshot EBS est une copie incrémentale stockée dans S3 (côté AWS). En Terraform : aws_ebs_snapshot (source = volume_id).
Aperçu minimal (illustratif — ne créez pas de snapshot durable en lab gratuit) :
# Illustratif — décommentez seulement pour un test court, puis destroy
# resource "aws_ebs_snapshot" "data" {
# volume_id = aws_ebs_volume.data.id
# description = "Lab snapshot ${var.project} — à détruire"
# tags = {
# Lab = "terraform-ebs"
# }
# }
Coûts / bonnes pratiques :
| Sujet | Conseil P2 |
|---|---|
| Stockage snapshot | Facturé même après destroy du volume — destroy le snapshot aussi |
| Incrémental | Premier snapshot ≈ taille utilisée ; suivants = deltas |
| Lifecycle | En prod : AWS Backup / DLM — pas des snapshots orphelins manuels |
| Lab | Préférez ne pas snapshotter ; si test : destroy immédiat |
| Restauration | Nouveau aws_ebs_volume avec snapshot_id (même Region ; AZ à choisir) |
Message SEO : terraform ebs sans gouvernance de snapshots = dette cloud silencieuse.
Étape 5 — Lab minimal ca-central-1 + destroy
Objectif : un volume gp3 8 Gio chiffré, sans EC2 obligatoire.
mkdir -p ~/terraform-ebs-lab && cd ~/terraform-ebs-lab
# Collez versions.tf, providers.tf, variables.tf, main.tf (étape 2)
# Option attach_existing : laissez false / omettez le bloc attachment
export AWS_PROFILE=lab
export AWS_REGION=ca-central-1
PROJECT="votreprenom20260910"
terraform init
terraform fmt
terraform validate
terraform plan -var="project=${PROJECT}"
terraform apply -auto-approve -var="project=${PROJECT}"
terraform output
# volume_id = vol-...
# volume_az = ca-central-1a
aws ec2 describe-volumes
--volume-ids "$(terraform output -raw volume_id)"
--region ca-central-1
--query 'Volumes[0].{State:State,Size:Size,Type:VolumeType,Encrypted:Encrypted}'
# Destroy obligatoire — ne laissez pas le volume (ni snapshot)
terraform destroy -auto-approve -var="project=${PROJECT}"
cd ~
rm -rf ~/terraform-ebs-lab
Vérification console / CLI : aucun vol- tagué Lab=terraform-ebs ne doit rester en ca-central-1. Si vous avez créé un snapshot de test : aws ec2 describe-snapshots --owner-ids self puis suppression.
Étape 6 — Checklist
- Distinguer EBS (persistant, AZ-bound) et instance store (éphémère).
- Déclarer
aws_ebs_volume:type = "gp3",sizepetit,encrypted = true, tags. - Comprendre
aws_volume_attachment: même AZ,device_name, instance requise. - Traiter les snapshots comme des ressources payantes à lifecycle / destroy.
- Lab en
ca-central-1, TF ≥ 1.9, provider~> 5.0. - Jamais de secrets / clés KMS CMK en clair dans le dépôt.
terraform destroy+ vérif absence de volumes/snapshots orphelins.
Nettoyage
cd ~/terraform-ebs-lab
PROJECT="votreprenom20260910"
terraform destroy -auto-approve -var="project=${PROJECT}"
cd ~
rm -rf ~/terraform-ebs-lab
# Filet de sécurité (si apply manuel hors state)
# aws ec2 describe-volumes --filters Name=tag:Lab,Values=terraform-ebs --region ca-central-1
# aws ec2 describe-snapshots --owner-ids self --filters Name=tag:Lab,Values=terraform-ebs --region ca-central-1
Erreurs fréquentes
| Symptôme | Cause | Correction |
|---|---|---|
InvalidVolume.ZoneMismatch / attachment refused |
Volume et instance dans des AZ différentes | Aligner availability_zone du volume sur l’AZ de l’instance (ca-central-1a ≠ 1b) |
Erreur KMS / Client.InvalidKMSKey |
kms_key_id invalide, mauvaise Region, ou IAM sans kms:CreateGrant |
Lab : encrypted = true sans CMK custom ; prod : policy KMS + même Region |
Volume in-use, destroy bloqué |
Attachment encore présent | Destroy l’aws_volume_attachment (ou détacher) avant le volume |
| Coût après destroy volume | Snapshots restants | Destroy / supprimer les snapshots tagués lab |
device_name déjà pris |
Conflit /dev/xvdf |
Autre lettre (xvdg…) ou inspecter les volumes attachés |
| Plan recrée le volume | Changement AZ / encrypted / type incompatible |
Attendu : certains attributs forcent replace — backup avant |
| Attach sans formatage | HCL OK, OS sans FS | SSM / user_data pour mkfs + mount — pas un provisioner |
Quiz (3 questions)
1. Un volume EBS est lié à :
- A. Toute la Region (multi-AZ natif)
- B. Une Availability Zone précise
- C. Uniquement à l’instance store de l’hôte
2. Pour un lab Free Tier friendly avec terraform ebs, quel type privilégier ?
- A.
io21000 Gio - B.
gp3petit (ex. 8 Gio), encrypted - C. Instance store uniquement
3. Après terraform destroy du volume, que vérifier encore ?
- A. Rien — le destroy couvre toujours les snapshots
- B. Les snapshots orphelins (coût stockage) et tags Lab
- C. Uniquement le provider version
Réponses : 1‑B · 2‑B · 3‑B
Pourquoi / quand gérer EBS avec Terraform
Un volume EBS survit (selon config) au cycle d’une instance : bases de données, disques de données, disques transitoires que vous voulez quand même tracer en IaC. Terraform rend explicites taille, type (gp3), chiffrement, AZ et attachement. Utilisez ce lab quand vous maîtrisez déjà Workflow, Variables et un minimum d’EC2 (instance + SG).
EBS vs instance store — rappel
| EBS | Instance store | |
|---|---|---|
| Persistance | Volume réseau, snapshotable | Disque hôte, éphémère |
| AZ | Lié à une AZ | Lié à l’instance |
| Cas d’usage | Données à conserver / déplacer | Cache, scratch |
| Terraform | aws_ebs_volume, attachment, snapshot |
Rarement « géré » comme volume durable |
Pièges EBS fréquents (au-delà du tableau d’erreurs)
- Volume créé en
ca-central-1aet instance en1b: attachement impossible. - Snapshots oubliés après destroy du volume : facturation silencieuse.
encrypted = trueavec CMK custom sans droitskms:CreateGrant: apply cassé — en lab, chiffrement géré AWS suffit.- Modifier un attribut force-new (AZ, certains flags) sans backup : replace destructeur.
- Formater/monter dans un provisioner Terraform : préférez user_data / SSM (voir tuto Provisioners — pourquoi les éviter).
- Laisser une instance + volume allumés hors lab : destroy et vérifiez volumes/snapshots tagués.
Quand créer le volume séparément vs block device intégré
- Block device dans
aws_instance: simple pour le disque racine / disques liés au lifecycle instance. aws_ebs_volume+aws_volume_attachment: disque de données que vous voulez détacher, snapshotter, réattacher ailleurs.
Ce tuto privilégie le second pour rendre visibles attachment et AZ.
Coût et Free Tier (discipline)
Choisissez gp3 petit (ex. 8 Gio), Region ca-central-1, chiffrement activé, tags Lab. Pas d’io2 provisionné, pas de milliers de Gio « pour voir ». Terraform ≥ 1.9, provider ~> 5.0, aucun secret / ARN KMS sensible en clair dans Git.
FAQ terraform EBS
Le destroy détache-t-il automatiquement ? L’ordre du graphe gère attachment puis volume si tout est dans le state ; un attachment orphelin hors state bloque encore.
Puis-je étendre la taille sans recreate ? Souvent update in-place côté AWS/Terraform selon l’attribut ; lisez le plan. L’OS doit ensuite étendre le système de fichiers.
Snapshots via Terraform ? Oui (aws_ebs_snapshot) ; traitez-les comme resources payantes avec lifecycle clair.
Multi-AZ pour un même volume ? Non : un volume EBS = une AZ. Pour multi-AZ, architecture (réplication, EFS, etc.).
Tags obligatoires ? Fortement recommandés (Project, Lab, Name) pour le filet de sécurité CLI post-lab.
SSM plutôt que SSH pour mkfs ? Oui dans l’esprit de la série AWS (moins de clés SSH à gérer).
Que vérifier après destroy ? describe-volumes / describe-snapshots filtrés sur vos tags en ca-central-1.
Pour aller plus loin
- Doc :
aws_ebs_volume,aws_volume_attachment,aws_ebs_snapshot, EBS pricing - Sur ce site : Provisioners, Workspaces, série AWS EBS volumes/snapshots ; suite ALB
Maillage série Terraform (P2)
| ← Précédent | Provisioners (terraform-provisioners) |
| → Suivant | ALB (terraform-alb) |
| Aussi | IAM (aws-iam-users-groupes-roles-politiques) · VPC (aws-vpc-sous-reseaux-igw) |
| Carte | Overview · Install · Workflow · Blocks · Providers · Variables · Locals · State · Modules · Workspaces · Labs AWS |
Cas réel — un volume orphelin après destroy d’instance
Sans aws_volume_attachment (ou l’équivalent root géré), un EBS survit et facture. Le lab impose destroy + vérif CLI. En prod, les tags Lab / ManagedBy servent précisément à retrouver ces orphelins. Snapshot avant resize : un type de volume changé n’est pas toujours in-place.
Piège : attacher le même volume à deux instances « pour aller vite ». AWS refuse ou corrompt. Un volume = un attachement actif. Multi-AZ : le volume vit dans une AZ ; le déplacer n’est pas un update de tag.
À retenir : EBS est persistant par défaut. Votre destroy de lab doit le prouver, pas le supposer.
Retour parcours Terraform — hub de la série et leçons sœurs.



