Terraform : Infrastructure as Code

Terraform : Infrastructure as Code

Provisionnez votre infrastructure de facon declarative avec Terraform. Multi-cloud (AWS, Azure, GCP, OVH, Hetzner, Scaleway), state remote, modules reutilisables. La reference Infrastructure as Code depuis 2014.

Introduction

Terraform vous permet de :

  • Decrire votre infra en code HCL (HashiCorp Configuration Language)
  • Provisionner serveurs, reseau, DNS, certificats sur tous les clouds
  • Gerer le state (qui possede quoi)
  • Planifier les changements avant application
  • Versionner votre infra dans Git

Cas d'usage : creer 100 VPS identiques, monter un cluster K8s sur AWS, gerer DNS Cloudflare en code, etc.

Note : depuis 2023, Terraform est sous licence BSL (commerciale). Le fork community OpenTofu garde la licence open-source MPL. Ce tuto utilise terraform mais tout fonctionne pareil avec tofu.

Prerequis

  • VPS Linux ou poste de travail Linux / macOS / Windows
  • Compte sur un cloud provider (AWS, Hetzner, OVH, etc.)
  • Acces root (pour install)

Etape 1 : Installation

Debian / Ubuntu

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt install -y terraform
terraform version

Ou OpenTofu

curl -fsSL https://get.opentofu.org/install-opentofu.sh | sudo sh -s -- --install-method deb
tofu version

Etape 2 : Premier project (Hetzner Cloud)

Creez un dossier :

mkdir ~/infra-hetzner && cd ~/infra-hetzner

main.tf :

terraform {
  required_providers {
    hcloud = {
      source = "hetznercloud/hcloud"
      version = "~> 1.45"
    }
  }
}

provider "hcloud" {
  token = var.hcloud_token
}

variable "hcloud_token" {
  type      = string
  sensitive = true
}

resource "hcloud_server" "web1" {
  name        = "web1"
  image       = "debian-12"
  server_type = "cx22"
  location    = "fsn1"
  ssh_keys    = [hcloud_ssh_key.default.id]
}

resource "hcloud_ssh_key" "default" {
  name       = "ma-cle"
  public_key = file("~/.ssh/id_ed25519.pub")
}

output "server_ip" {
  value = hcloud_server.web1.ipv4_address
}

Etape 3 : Initialiser

terraform init

Telecharge le provider Hetzner. Cree .terraform/ et .terraform.lock.hcl.

Etape 4 : Plan

export TF_VAR_hcloud_token="votre-token-hetzner"
terraform plan

Affiche les changements (creations, modifications, destructions). Lisez toujours le plan attentivement avant d'apply.

Etape 5 : Apply

terraform apply

Tapez yes pour confirmer. Terraform cree le serveur Hetzner. A la fin :

Outputs:
server_ip = "5.78.123.45"

SSH dessus :

ssh [email protected]

Etape 6 : State

Le state est dans terraform.tfstate. Il contient l'etat actuel de votre infra (ressources, IDs, attributs).

⚠️ Ne le commitez jamais dans Git. Mettez-le dans .gitignore.

echo "*.tfstate*" >> .gitignore
echo ".terraform/" >> .gitignore

Pour le travail en equipe, utilisez un backend distant.

Etape 7 : Backend distant (S3)

backend.tf :

terraform {
  backend "s3" {
    bucket = "monequipe-terraform-state"
    key    = "infra-hetzner/terraform.tfstate"
    region = "eu-west-3"
    encrypt = true
  }
}
terraform init -migrate-state

State est maintenant sur S3, partage entre membres de l'equipe. Utilisez DynamoDB pour le locking (eviter applies concurrents).

Alternatives a S3 : Terraform Cloud (managed), Scalr, Spacelift, ou backend HTTP custom.

Etape 8 : Variables et environments

variables.tf :

variable "environment" {
  type    = string
  default = "dev"
}

variable "server_type" {
  type = string
  default = "cx22"
}

locals {
  common_tags = {
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

Utilisation :

resource "hcloud_server" "web" {
  name        = "${var.environment}-web"
  server_type = var.server_type
  labels      = local.common_tags
}

Variables via fichier .tfvars :

prod.tfvars :

environment = "prod"
server_type = "ccx33"
terraform apply -var-file=prod.tfvars

Etape 9 : Modules

Encapsulez du code reutilisable dans un module :

modules/
  webapp/
    main.tf
    variables.tf
    outputs.tf

modules/webapp/main.tf :

resource "hcloud_server" "web" {
  name        = var.name
  image       = "debian-12"
  server_type = var.server_type
  location    = var.location
  ssh_keys    = var.ssh_keys
}

Utilisation :

module "web1" {
  source      = "./modules/webapp"
  name        = "web1"
  server_type = "cx22"
  location    = "fsn1"
  ssh_keys    = [hcloud_ssh_key.default.id]
}

module "web2" {
  source      = "./modules/webapp"
  name        = "web2"
  server_type = "cx32"
  location    = "nbg1"
  ssh_keys    = [hcloud_ssh_key.default.id]
}

Ou utilisez des modules communautaires : https://registry.terraform.io

Etape 10 : Provisioning (cloud-init)

Pour configurer le serveur a sa creation :

resource "hcloud_server" "web" {
  name        = "web"
  image       = "debian-12"
  server_type = "cx22"
  location    = "fsn1"
  
  user_data = <<-EOT
    #cloud-config
    package_update: true
    packages:
      - nginx
      - certbot
    runcmd:
      - systemctl enable nginx
      - echo "Hello from terraform" > /var/www/html/index.html
  EOT
}

Pour des configurations complexes, deleguez a Ansible apres provisioning Terraform.

Etape 11 : Destroy

terraform destroy

⚠️ Detruit toute l'infra geree par ce state. Faites attention.

Detruire une seule ressource :

terraform destroy -target=hcloud_server.web1

Etape 12 : Workflow pro

Le workflow standard en equipe :

# 1. Pull la derniere version
git pull

# 2. Format et validate
terraform fmt -recursive
terraform validate

# 3. Plan
terraform plan -out=tfplan

# 4. Review le plan (ou code review via PR)
terraform show tfplan

# 5. Apply le plan exact
terraform apply tfplan

# 6. Commit + push
git add . && git commit -m "Ajout web1" && git push

En CI, utilisez Atlantis ou Terraform Cloud pour automatiser les plan + apply via PR.

Depannage

"Error: Provider not found"

terraform init -upgrade

State lock

Si un autre terraform tourne ou a crashe :

terraform force-unlock LOCK_ID

Verifiez d'abord que personne ne fait apply en parallele.

"resource already exists"

Vous avez cree une ressource hors terraform. Importez-la :

terraform import hcloud_server.web1 12345

Drift (ressource modifiee a la main)

terraform plan

Affiche le drift. apply re-aligne. Ou ajustez votre code pour matcher la realite.

"Provider produced inconsistent final plan"

Bug du provider. Mettez a jour :

terraform init -upgrade

Commandes utiles

terraform init                       # init du project
terraform plan                       # voir les changements
terraform apply                      # appliquer
terraform destroy                    # tout detruire
terraform fmt -recursive             # formatter
terraform validate                   # valider syntaxe
terraform show                       # voir le state

terraform state list                 # lister les ressources
terraform state show <resource>      # voir le detail
terraform state rm <resource>        # retirer du state (sans destroy)
terraform state mv <from> <to>       # renommer dans le state

terraform import <resource> <id>     # importer existing

terraform output                     # voir les outputs
terraform output -json               # json

terraform workspace list             # workspaces (envs paralleles)
terraform workspace new staging
terraform workspace select staging

Conclusion

Terraform vous donne :

  • Infrastructure declarative et versionnee
  • Multi-cloud
  • State management pour le travail en equipe
  • Modules reutilisables

Pour aller plus loin :

  • Utilisez Atlantis ou Terraform Cloud pour le workflow CI/CD
  • Combinez avec Ansible pour configurer apres provisioning
  • Pour Kubernetes, regardez Pulumi ou Crossplane (k8s-native)
  • Pour rester open-source, migrez vers OpenTofu

Ressources

Rejoignez notre serveur communautaire Discord

Pour toute question, suggestion ou simplement pour discuter avec la communauté, rejoignez-nous sur Discord !

900+Membres