TP partie 6 - État Terraform et workspaces
Dans cette sixième partie, nous allons explorer en profondeur la gestion de l’état (state) dans Terraform et l’utilisation des workspaces pour gérer des environnements temporaires et des tests de fonctionnalités.
Étude de l’état Terraform
Section titled “Étude de l’état Terraform”L’état Terraform est un fichier JSON qui maintient la correspondance entre votre configuration et les ressources réelles dans le cloud. Nous allons explorer cet élément fondamental de Terraform.
Analyse du fichier d’état local
Section titled “Analyse du fichier d’état local”Partez du code de la partie 5 (copiez le dossier ou commitez les changements). Dans le dossier part6, assurez vous du bon déploiement l’infrastructure (avoir un état) :
terraform initterraform plan -var-file="feature-a.tfvars" -out=tfplanterraform apply tfplanExploration via la CLI Terraform
Section titled “Exploration via la CLI Terraform”Utilisez les commandes Terraform pour inspecter l’état :
# Lister toutes les ressources dans l'étatterraform state list
# Afficher les détails d'une ressourceterraform state show aws_vpc.main
# Afficher l'état complet en format lisibleterraform show
# Afficher l'état en format JSONterraform show -json > state.jsonCes commandes permettent d’explorer l’état sans le modifier. Vous y trouverez les identifiants des ressources (IDs AWS), les métadonnées de création, les dépendances entre ressources et les attributs sensibles (marqués comme tels).
Structure du fichier terraform.tfstate
Section titled “Structure du fichier terraform.tfstate”Ouvrez le fichier terraform.tfstate dans votre éditeur pour examiner sa structure. C’est un fichier JSON lisible qui contient toute l’information sur votre infrastructure :
{ "version": 4, "terraform_version": "1.5.7", "serial": 42, "lineage": "8a8b6c91-f6f7-c289-66f7-1b4e5dca8d50", "outputs": { "web_url": { "value": "http://13.37.42.10", "type": "string" } }, "resources": [ { "mode": "managed", "type": "aws_vpc", "name": "main", "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]", "instances": [ { "schema_version": 1, "attributes": { "id": "vpc-0123456789abcdef0", "cidr_block": "10.0.0.0/16", "tags": { "Name": "main-vpc" } } } ] } ]}Éléments importants de la structure :
- version : Version du format de fichier d’état (actuellement 4)
- terraform_version : Version de Terraform qui a créé cet état
- serial : Compteur incrémenté à chaque modification pour éviter les conflits
- lineage : UUID unique généré à la création de l’état, reste constant pendant toute sa vie
- outputs : Valeurs de sortie de votre configuration
- resources : Liste complète des ressources avec leurs attributs AWS réels
Chaque ressource contient :
- mode : “managed” (créée par Terraform) ou “data” (source de données)
- type et name : Correspondent à votre configuration (ex:
aws_vpc.main) - provider : Provider utilisé pour gérer cette ressource
- instances : Détails de chaque instance de la ressource avec tous ses attributs
Le fichier terraform.tfstate.backup
Section titled “Le fichier terraform.tfstate.backup”Terraform crée automatiquement un fichier terraform.tfstate.backup qui contient la version précédente de l’état avant la dernière modification. Ce fichier de sauvegarde est crucial pour la récupération en cas de problème :
- Créé automatiquement à chaque
terraform applyou modification d’état - Contient l’état exact d’avant la dernière opération
- Permet de revenir en arrière en cas de corruption ou d’erreur
- Ne doit pas être commité dans Git mais peut être sauvegardé séparément
En cas de problème grave avec l’état, vous pouvez restaurer manuellement :
# En dernier recours uniquement !cp terraform.tfstate.backup terraform.tfstate⚠️ Important : Ne modifiez jamais directement les fichiers d’état. Utilisez toujours les commandes Terraform pour toute manipulation.
Commandes avancées d’état
Section titled “Commandes avancées d’état”# Importer une ressource existante dans l'état# terraform import aws_vpc.main vpc-1234567890abcdef0
# Retirer une ressource de l'état sans la détruire# terraform state rm aws_instance.web_server
# Déplacer une ressource dans l'état# terraform state mv aws_instance.web_server aws_instance.web_server_renamed
# Remplacer une ressource# terraform state replace-provider hashicorp/aws registry.terraform.io/hashicorp/awsWorkspaces : cas d’usage et limitations
Section titled “Workspaces : cas d’usage et limitations”Les workspaces Terraform permettent de créer plusieurs instances isolées d’une même configuration, chacune avec son propre fichier d’état. Contrairement à une idée répandue, ils ne sont pas la solution idéale pour séparer des environnements critiques comme production et développement. Il est facile de faire des erreurs avec en tout cas manuellement. Pour séparer dev et prod il on utilise plus classiquement deux backend séparés (avec un authentification et un code distinct qu’on peut factoriser avec des modules)
Comprendre les workspaces
Section titled “Comprendre les workspaces”Par défaut, Terraform utilise un workspace nommé “default” :
# Voir le workspace actuelterraform workspace show
# Créer et sélectionner un nouveau workspaceterraform workspace new feature-testterraform workspace select feature-test
# Lister tous les workspacesterraform workspace listChaque workspace possède son propre fichier d’état, stocké dans le même backend mais dans des chemins séparés (ici avec un backend local terraform.state.d).
Cas d’usage appropriés pour les workspaces
Section titled “Cas d’usage appropriés pour les workspaces”Les workspaces sont particulièrement adaptés pour :
Tests de branches de fonctionnalités : Déployer temporairement une branche pour tests sans impacter l’environnement principal de développement.
Déploiements multi-régions : Déployer la même application dans plusieurs régions AWS avec des variations mineures.
Environnements temporaires : Créer des environnements éphémères pour des démonstrations ou des tests de charge.
Variantes d’une même application : Déployer plusieurs versions d’une application dans le même environnement (par exemple, différentes configurations pour différents clients).
Adaptation du code pour les workspaces
Section titled “Adaptation du code pour les workspaces”Pour utiliser les workspaces efficacement, nous devons adapter notre code de la partie 5. Voici les modifications nécessaires :
Ajout d’une nouvelle variable dans variables.tf :
variable "feature_name" { description = "Name of the feature being tested" type = string default = "main"}Utilisation de terraform.workspace dans vpc.tf :
Terraform expose le nom du workspace actuel via terraform.workspace. Modifiez toutes les ressources VPC pour utiliser cette valeur :
# VPC avec nom dynamique par workspaceresource "aws_vpc" "main" { cidr_block = var.vpc_cidr enable_dns_hostnames = true enable_dns_support = true
tags = { Name = "${terraform.workspace}-vpc" # Changé de "main-vpc" Workspace = terraform.workspace # Nouveau tag Feature = var.feature_name # Nouveau tag }}
# Internet Gatewayresource "aws_internet_gateway" "main" { vpc_id = aws_vpc.main.id
tags = { Name = "${terraform.workspace}-igw" # Changé de "main-igw" Workspace = terraform.workspace # Nouveau tag Feature = var.feature_name # Nouveau tag }}
# Subnet publicresource "aws_subnet" "public" { vpc_id = aws_vpc.main.id cidr_block = var.public_subnet_cidr map_public_ip_on_launch = true
tags = { Name = "${terraform.workspace}-public-subnet" # Changé de "public-subnet" Workspace = terraform.workspace # Nouveau tag Feature = var.feature_name # Nouveau tag }}
# Route tableresource "aws_route_table" "public" { vpc_id = aws_vpc.main.id
route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.main.id }
tags = { Name = "${terraform.workspace}-public-route-table" # Changé de "public-route-table" Workspace = terraform.workspace # Nouveau tag Feature = var.feature_name # Nouveau tag }}
# Security Group avec nom unique par workspaceresource "aws_security_group" "web_ssh_access" { name = "${terraform.workspace}-web-ssh-access" # Changé de "web-ssh-access" description = "Allow SSH and HTTP access for ${terraform.workspace}" vpc_id = aws_vpc.main.id
# ... règles inchangées ...
tags = { Name = "${terraform.workspace}-web-ssh-access" # Changé de "Web and SSH Access" Workspace = terraform.workspace # Nouveau tag Feature = var.feature_name # Nouveau tag }}Modification de webserver.tf avec user-data :
# Data source pour l'AMI Ubuntu standarddata "aws_ami" "ubuntu" { most_recent = true owners = ["099720109477"] # Canonical
filter { name = "name" values = ["ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"] }
filter { name = "virtualization-type" values = ["hvm"] }}
# Template pour user-datadata "template_file" "user_data" { template = <<-EOF#!/bin/bash
# Mettre à jour le systèmeapt-get update
# Créer l'utilisateur et configurer SSHif ! id "terraform" &>/dev/null; then useradd -m -s /bin/bash terraform usermod -aG sudo terraform echo 'terraform ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoersfi
# Créer le répertoire .sshmkdir -p /home/terraform/.sshchmod 700 /home/terraform/.ssh
# Ajouter la clé publique SSHecho "${ssh_public_key}" > /home/terraform/.ssh/authorized_keyschmod 600 /home/terraform/.ssh/authorized_keyschown -R terraform:terraform /home/terraform/.ssh
# Installer et configurer nginxapt-get install -y nginxsystemctl start nginxsystemctl enable nginx
# Créer la page d'accueil avec workspace et featureecho '<h1>Feature: ${feature_name} (${workspace})</h1>' > /var/www/html/index.htmlecho '<p>Serveur déployé avec user-data</p>' >> /var/www/html/index.html
echo "Configuration terminée avec user-data"EOF
vars = { ssh_public_key = file("${var.ssh_key_path}.pub") feature_name = var.feature_name workspace = terraform.workspace }}
# Instance EC2 avec user-dataresource "aws_instance" "web_server" { ami = data.aws_ami.ubuntu.id instance_type = var.instance_type subnet_id = aws_subnet.public.id vpc_security_group_ids = [aws_security_group.web_ssh_access.id] user_data = data.template_file.user_data.rendered
tags = { Name = "${terraform.workspace}-web-server" # Changé de "nginx-web-server-vpc" Workspace = terraform.workspace # Nouveau tag Feature = var.feature_name # Nouveau tag }}Création du fichier feature-a.tfvars pour tester une fonctionnalité spécifique :
aws_region = "eu-west-3"aws_profile = "default"vpc_cidr = "10.100.0.0/16"public_subnet_cidr = "10.100.1.0/24"instance_type = "t2.micro"ssh_key_path = "~/.ssh/id_terraform"feature_name = "feature-payment-api"Ces modifications permettent à chaque workspace d’avoir des noms de ressources uniques et d’afficher clairement dans quel contexte il fonctionne.
Déploiement de branches de fonctionnalités
Section titled “Déploiement de branches de fonctionnalités”# Déploiement de la branche feature-paymentterraform workspace new feature-paymentterraform plan -var-file="feature-a.tfvars" -out=feature.tfplanterraform apply feature.tfplan
# Retour au workspace principalterraform workspace select default
# Nettoyage après les teststerraform workspace select feature-paymentterraform destroy -var-file="feature-a.tfvars"terraform workspace select defaultterraform workspace delete feature-paymentLimitations des workspaces pour les environnements
Section titled “Limitations des workspaces pour les environnements”Les workspaces présentent des limitations importantes pour la séparation d’environnements critiques :
Même backend partagé : Tous les workspaces utilisent le même backend S3, donc les mêmes permissions d’accès. Impossible d’isoler réellement production et développement.
Manque de visibilité et Risque d’erreurs humaines : Le workspace actuel n’est pas visible dans le code. Un terraform destroy ou mauvaise modification dans le mauvais workspace peut avoir des conséquences catastrophiques.
Pas de séparation des pipelines : Plus difficile d’avoir des processus CI/CD différents par workspace.
Alternative recommandée pour les environnements
Section titled “Alternative recommandée pour les environnements”Pour une vraie séparation dev/staging/prod, privilégiez :
# Structure de répertoires séparésterraform-infra/├── environments/│ ├── dev/│ │ ├── main.tf│ │ ├── backend.tf # Backend S3 différent│ │ └── terraform.tfvars│ ├── staging/│ │ ├── main.tf│ │ ├── backend.tf # Backend S3 différent│ │ └── terraform.tfvars│ └── prod/│ ├── main.tf│ ├── backend.tf # Backend S3 différent│ └── terraform.tfvars└── modules/ ├── vpc/ └── webserver/Cette approche offre une vraie isolation avec des backends séparés, des permissions différentes et des pipelines CI/CD distincts. nous verrons cela dans un TP suivant.
Gestion des états par workspace
Section titled “Gestion des états par workspace”Chaque workspace maintient son propre fichier d’état. Pour un backend local :
# Les états sont stockés dans# terraform.tfstate.d/feature-auth/terraform.tfstate
ls -la terraform.tfstate.d/Pour un backend S3, les états sont organisés avec le préfixe env: :
s3://bucket-name/env:/feature-payment/path/to/states3://bucket-name/env:/feature-auth/path/to/statePoints clés à retenir :
- L’état Terraform est le cœur de votre infrastructure et doit être protégé
- Les workspaces sont utiles pour des variations temporaires, pas pour isoler prod/dev
- Pour de vrais environnements séparés, utilisez des répertoires et backends distincts
- Les workspaces permettent de tester des branches de fonctionnalités de manière isolée
Dans la partie suivante, nous configurerons un backend S3 distant avec verrouillage DynamoDB pour permettre la collaboration sécurisée entre développeurs.