Introduction
Installation
Concepts
Syntaxe HCL
Providers
Variables
Modules
State
Commandes
Bonnes Pratiques
Exercices
đ Introduction Ă Terraform
Qu'est-ce que Terraform ?
Terraform est un outil open-source développé par HashiCorp qui permet de définir, déployer et gérer l'infrastructure cloud à travers du code (Infrastructure as Code - IaC).
đïž Infrastructure as Code
Définir l'infrastructure avec du code déclaratif plutÎt que par des processus manuels.
đ Multi-Provider
Support de multiples fournisseurs cloud (AWS, Azure, GCP, etc.) avec une syntaxe unifiée.
đ Ătat de l'Infrastructure
Suivi automatique de l'état actuel de votre infrastructure.
đŻ DĂ©claratif
Décrivez ce que vous voulez, Terraform détermine comment l'obtenir.
Avantages de Terraform
ReproductibilitĂ© : MĂȘme infrastructure dĂ©ployable dans diffĂ©rents environnements
Versionning : Infrastructure versionnée avec Git
Collaboration : Ăquipes peuvent travailler ensemble sur l'infrastructure
Planification : Prévisualisation des changements avant application
Automatisation : Intégration dans les pipelines CI/CD
đĄ Conseil : Terraform est idĂ©al pour gĂ©rer l'infrastructure de production de maniĂšre cohĂ©rente et prĂ©visible. Commencez par des ressources simples avant de passer Ă des architectures complexes.
âïž Installation et Configuration
Installation de Terraform
Linux / macOS
# Télécharger Terraform
wget https://releases.hashicorp.com/terraform/1.6.0/terraform_1.6.0_linux_amd64.zip
# Décompresser l'archive
unzip terraform_1.6.0_linux_amd64.zip
# Déplacer vers /usr/local/bin
sudo mv terraform /usr/local/bin/
# Installation via Homebrew (macOS)
brew install terraform
# Installation via APT (Ubuntu/Debian)
sudo apt-get install terraform
Windows
# Installation via Chocolatey
choco install terraform
# Alternative : téléchargement manuel
# Aller sur https://www.terraform.io/downloads.html
Vérification de l'installation
# Vérifier la version installée
terraform version
# Afficher l'aide
terraform -help
Configuration des providers
# Définir l'Access Key AWS
export AWS_ACCESS_KEY_ID="votre-access-key"
# Définir la Secret Key AWS
export AWS_SECRET_ACCESS_KEY="votre-secret-key"
# Définir la région par défaut AWS
export AWS_DEFAULT_REGION="eu-west-1"
# Se connecter Ă Azure
az login
# Définir les credentials Google Cloud
export GOOGLE_APPLICATION_CREDENTIALS="chemin/vers/service-account.json"
â ïž SĂ©curitĂ© : Ne jamais hardcoder les credentials dans les fichiers Terraform. Utilisez les variables d'environnement ou des services de gestion de secrets.
đŻ Concepts Fondamentaux
đ Configuration
Fichiers .tf qui décrivent l'infrastructure désirée en langage HCL (HashiCorp Configuration Language).
đ Provider
Plugin qui permet Ă Terraform d'interagir avec des APIs (AWS, Azure, GCP, etc.).
đïž Resource
ĂlĂ©ment d'infrastructure (VM, rĂ©seau, base de donnĂ©es) gĂ©rĂ© par Terraform.
đ State
Fichier qui mappe la configuration Terraform aux ressources réelles.
đ Plan
Description des actions que Terraform va effectuer pour atteindre l'état désiré.
đŠ Module
Collection réutilisable de ressources Terraform.
Workflow Terraform
# Initialiser le répertoire de travail
terraform init
# Créer un plan d'exécution
terraform plan
# Appliquer les changements
terraform apply
# Détruire l'infrastructure
terraform destroy
đ Syntaxe HCL (HashiCorp Configuration Language)
Structure de base
# Commentaire explicatif
resource "aws_instance" "example" {
ami = "ami-0c55b159cbfafe1d0"
instance_type = "t2.micro"
tags = {
Name = "ExampleInstance"
}
}
Types de blocs
1. Provider
provider "aws" {
region = "eu-west-1"
}
provider "azurerm" {
features {}
}
2. Resource
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "main-vpc"
}
}
3. Data Source
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
4. Variables
variable "region" {
description = "AWS region"
type = string
default = "eu-west-1"
}
variable "instance_count" {
description = "Number of instances"
type = number
default = 2
}
5. Outputs
output "instance_ip" {
description = "Public IP of the instance"
value = aws_instance.example.public_ip
}
Types de données
map
{key1 = "value1", key2 = "value2"}
object
Structure complexe avec types typés
đ Providers et Resources
Configuration des Providers
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.0"
}
}
}
Providers populaires
đĄ AWS
Amazon Web Services - Le plus utilisé
đ” Azure
Microsoft Azure - DeuxiĂšme plus populaire
đŽ GCP
Google Cloud Platform
đŁ Kubernetes
Gestion des ressources Kubernetes
đą Docker
Gestion des conteneurs Docker
â« Null
Exécution de scripts et provisioners
Exemples de Resources
AWS EC2 Instance
resource "aws_instance" "web_server" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.web.id]
subnet_id = aws_subnet.public.id
user_data = <<-EOF
#!/bin/bash
apt-get update
apt-get install -y nginx
systemctl start nginx
systemctl enable nginx
EOF
tags = {
Name = "WebServer"
Environment = "prod"
}
}
Azure Virtual Machine
resource "azurerm_virtual_machine" "main" {
name = "acctvm"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
network_interface_ids = [azurerm_network_interface.main.id]
vm_size = "Standard_DS1_v2"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
storage_os_disk {
name = "myosdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
}
đ Documentation : Chaque provider a sa propre documentation avec tous les resources disponibles. Consultez registry.terraform.io pour les dĂ©tails.
đ§ Variables et Outputs
Déclaration de Variables
variable "environment" {
description = "Environment name"
type = string
default = "dev"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Environment must be dev, staging, or prod."
}
}
variable "instance_config" {
description = "Instance configuration"
type = object({
instance_type = string
disk_size = number
public_ip = bool
})
default = {
instance_type = "t3.micro"
disk_size = 20
public_ip = false
}
}
Utilisation des Variables
resource "aws_instance" "example" {
ami = var.ami_id
instance_type = var.instance_config.instance_type
root_block_device {
volume_size = var.instance_config.disk_size
}
tags = {
Name = "${var.environment}-instance"
}
}
Fichiers de Variables
terraform.tfvars
environment = "prod"
region = "eu-west-1"
instance_config = {
instance_type = "t3.small"
disk_size = 50
public_ip = true
}
Variables d'environnement
# Définir la variable d'environnement pour l'environment
export TF_VAR_environment="prod"
# Définir la variable d'environnement pour la région
export TF_VAR_region="eu-west-1"
Outputs
output "instance_public_ip" {
description = "Public IP address of the instance"
value = aws_instance.example.public_ip
sensitive = false
}
output "vpc_id" {
description = "VPC ID"
value = aws_vpc.main.id
}
output "database_connection" {
description = "Database connection string"
value = aws_db_instance.main.endpoint
sensitive = true
}
Local Values
locals {
common_tags = {
Environment = var.environment
Project = "MyProject"
ManagedBy = "Terraform"
}
instance_name = "${var.environment}-${var.application_name}"
}
resource "aws_instance" "example" {
ami = var.ami_id
instance_type = var.instance_type
tags = merge(local.common_tags, {
Name = local.instance_name
})
}
đŠ Modules Terraform
Qu'est-ce qu'un Module ?
Un module est un conteneur pour plusieurs ressources utilisées ensemble. Chaque configuration Terraform comprend au moins un module, appelé module racine.
Structure d'un Module
modules/
âââ vpc/
âââ main.tf # Resources principales
âââ variables.tf # DĂ©clarations de variables
âââ outputs.tf # DĂ©clarations d'outputs
âââ README.md # Documentation
Exemple de Module VPC
modules/vpc/main.tf
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
enable_dns_hostnames = var.enable_dns_hostnames
enable_dns_support = var.enable_dns_support
tags = merge(var.tags, {
Name = var.name
})
}
resource "aws_subnet" "public" {
count = length(var.public_subnets)
vpc_id = aws_vpc.main.id
cidr_block = var.public_subnets[count.index]
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = merge(var.tags, {
Name = "${var.name}-public-${count.index + 1}"
Type = "public"
})
}
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = merge(var.tags, {
Name = "${var.name}-igw"
})
}
modules/vpc/variables.tf
variable "name" {
description = "Name prefix for resources"
type = string
}
variable "cidr_block" {
description = "CIDR block for VPC"
type = string
default = "10.0.0.0/16"
}
variable "public_subnets" {
description = "List of public subnet CIDR blocks"
type = list(string)
default = ["10.0.1.0/24", "10.0.2.0/24"]
}
variable "availability_zones" {
description = "List of availability zones"
type = list(string)
}
variable "enable_dns_hostnames" {
description = "Enable DNS hostnames in VPC"
type = bool
default = true
}
variable "tags" {
description = "Tags to apply to resources"
type = map(string)
default = {}
}
modules/vpc/outputs.tf
output "vpc_id" {
description = "ID of the VPC"
value = aws_vpc.main.id
}
output "public_subnet_ids" {
description = "IDs of the public subnets"
value = aws_subnet.public[*].id
}
output "internet_gateway_id" {
description = "ID of the Internet Gateway"
value = aws_internet_gateway.main.id
}
Utilisation d'un Module
module "vpc" {
source = "./modules/vpc"
name = "production"
cidr_block = "10.0.0.0/16"
public_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
availability_zones = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
tags = {
Environment = "production"
Project = "MyApp"
}
}
# Utilisation des outputs du module
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1d0"
instance_type = "t3.micro"
subnet_id = module.vpc.public_subnet_ids[0]
}
Modules depuis le Registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "~> 5.0"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["eu-west-1a", "eu-west-1b", "eu-west-1c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
enable_nat_gateway = true
enable_vpn_gateway = true
tags = {
Terraform = "true"
Environment = "dev"
}
}
đ Gestion de l'Ătat (State)
Qu'est-ce que le State ?
Le fichier state (terraform.tfstate) mappe vos configurations Terraform aux ressources réelles. Il sert de "source de vérité" pour votre infrastructure.
đ Mapping
Lie la configuration aux ressources réelles
đ Performance
Cache les métadonnées pour éviter les appels API
đ Verrouillage
Prévient les modifications concurrentes
đ Synchronisation
Assure la cohérence en équipe
Backend Configuration
Local Backend (par défaut)
terraform {
backend "local" {
path = "terraform.tfstate"
}
}
S3 Backend (Recommandé)
terraform {
backend "s3" {
bucket = "my-terraform-state-bucket"
key = "infrastructure/terraform.tfstate"
region = "eu-west-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Azure Backend
terraform {
backend "azurerm" {
resource_group_name = "tfstate"
storage_account_name = "tfstate0123456789"
container_name = "tfstate"
key = "infrastructure.tfstate"
}
}
Commandes State
# Lister toutes les ressources dans le state
terraform state list
# Afficher les détails d'une ressource spécifique
terraform state show aws_instance.example
# Télécharger le state depuis le backend
terraform state pull
# Envoyer le state vers le backend
terraform state push
# Déplacer une ressource dans le state
terraform state mv aws_instance.old aws_instance.new
# Supprimer une ressource du state
terraform state rm aws_instance.example
Import de Ressources
# Importer une ressource existante dans le state
terraform import aws_instance.example i-0123456789abcdef0
# Configuration minimale pour l'import (dans un fichier .tf)
resource "aws_instance" "example" {
ami = "ami-12345678"
instance_type = "t2.micro"
}
â ïž Attention : Ne jamais Ă©diter manuellement le fichier state. Utilisez toujours les commandes Terraform pour le modifier.
⥠Commandes Terraform
Commandes de Base
# Initialiser un répertoire Terraform
terraform init
# Créer un plan d'exécution
terraform plan
# Appliquer les modifications
terraform apply
# Détruire l'infrastructure
terraform destroy
# Valider la syntaxe des fichiers
terraform validate
# Formater les fichiers Terraform
terraform fmt
# Afficher l'état ou le plan
terraform show
# Afficher les valeurs de sortie
terraform output
# Mettre à jour l'état avec la réalité
terraform refresh
# Générer un graphique des dépendances
terraform graph
Options Utiles
# Plan avec fichier de variables spécifique
terraform plan -var-file="prod.tfvars"
# Apply avec confirmation automatique
terraform apply -auto-approve
# Apply uniquement certaines ressources
terraform apply -target=aws_instance.web
# Plan avec sortie dans un fichier
terraform plan -out=tfplan
# Apply depuis un plan sauvegardé
terraform apply tfplan
# Destroy avec confirmation automatique
terraform destroy -auto-approve
# Validation sans couleurs
terraform validate -no-color
# Format récursif de tous les fichiers
terraform fmt -recursive
Workspace Management
# Lister les workspaces
terraform workspace list
# Créer un nouveau workspace
terraform workspace new production
# Changer de workspace
terraform workspace select production
# Supprimer un workspace
terraform workspace delete staging
# Afficher le workspace actuel
terraform workspace show
â
Bonnes Pratiques
đ Structure de Projet
Organisez vos fichiers logiquement avec des modules réutilisables
đ SĂ©curitĂ©
Ne jamais exposer de credentials dans le code
đ State Management
Utilisez un backend distant pour le state
đ·ïž Tagging
Appliquez des tags cohérents à toutes les ressources
đ Versionning
Versionnez vos modules et configurations
đ§Ș Testing
Testez vos configurations avant la production
Structure de Projet Recommandée
terraform-infrastructure/
âââ environments/
â âââ dev/
â â âââ main.tf
â â âââ variables.tf
â â âââ outputs.tf
â â âââ terraform.tfvars
â âââ staging/
â âââ prod/
âââ modules/
â âââ vpc/
â âââ ec2/
â âââ rds/
âââ global/
â âââ s3/
â âââ iam/
âââ README.md
Conventions de Nommage
# Ressources
resource "aws_instance" "web_server" { # snake_case
name = "web-server-prod" # kebab-case pour noms
}
# Variables
variable "environment_name" { # snake_case
description = "Environment name"
}
# Modules
module "application_vpc" { # snake_case
source = "./modules/vpc"
}
Gestion des Secrets
# â JAMAIS comme ça
resource "aws_db_instance" "main" {
password = "super_secret_password" # JAMAIS !
}
# â
Utilisez des variables
resource "aws_db_instance" "main" {
password = var.db_password
}
# â
Ou des services managés
resource "aws_db_instance" "main" {
manage_master_user_password = true
}
Validation et Tests
# Vérifier le formatage des fichiers
terraform fmt -check
# Valider la configuration
terraform validate
# Créer un plan pour vérifier les changements
terraform plan
# Exemple de test Terratest (Go)
func TestTerraformExample(t *testing.T) {
terraformOptions := &terraform.Options{
TerraformDir: "../",
}
# Nettoyer aprĂšs les tests
defer terraform.Destroy(t, terraformOptions)
# Initialiser et appliquer
terraform.InitAndApply(t, terraformOptions)
# Ajouter ici vos tests spécifiques
}
đŻ Conseil Pro : Utilisez terraform plan avant chaque apply, mĂȘme en dĂ©veloppement. Cela vous aide Ă comprendre les changements et Ă©viter les surprises.
đ Exercices Pratiques
Exercice 1 : PremiĂšre Infrastructure
Objectif : Créer une instance EC2 simple avec un groupe de sécurité.
TĂąches :
Configurer le provider AWS
Créer un groupe de sécurité autorisant SSH (port 22)
Lancer une instance t3.micro Ubuntu
Afficher l'IP publique en output
Exercice 2 : Infrastructure avec Variables
Objectif : Refactoriser l'exercice 1 avec des variables.
TĂąches :
Créer des variables pour la région, type d'instance, AMI
Utiliser un fichier terraform.tfvars
Ajouter des tags variables
Implémenter des validations sur les variables
Exercice 3 : Module Réutilisable
Objectif : Créer un module pour déployer une application web.
TĂąches :
Créer un module avec VPC, subnets, et instances
Configurer un load balancer
Implémenter l'auto-scaling
Utiliser le module dans deux environnements
Exercice 4 : Backend Distant
Objectif : Configurer un backend S3 avec verrouillage DynamoDB.
TĂąches :
Créer un bucket S3 pour le state
Configurer une table DynamoDB pour le verrouillage
Migrer le state local vers S3
Tester le verrouillage avec deux terminaux
Solutions Types
Solution Exercice 1
# Configuration du provider AWS
provider "aws" {
region = "eu-west-1"
}
# Création d'un groupe de sécurité pour le web
resource "aws_security_group" "web" {
name_prefix = "web-sg"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# Récupération de l'AMI Ubuntu la plus récente
data "aws_ami" "ubuntu" {
most_recent = true
owners = ["099720109477"]
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
# Création de l'instance EC2
resource "aws_instance" "web" {
ami = data.aws_ami.ubuntu.id
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.web.id]
tags = {
Name = "WebServer"
}
}
# Output de l'adresse IP publique
output "public_ip" {
value = aws_instance.web.public_ip
}