TP 8 : Détecter une dérive avec Docker
Objectif
Section intitulée « Objectif »Comprendre ce que Terraform détecte lorsqu’une ressource gérée par Terraform est modifiée manuellement.
Ce TP permet de voir :
- la différence entre la configuration Terraform, le state et l’état réel
- le rôle de
terraform plan - ce que Terraform détecte après une modification manuelle
- ce que Terraform ne détecte pas forcément
- comment remettre l’infrastructure dans l’état attendu
Principe
Section intitulée « Principe »Terraform compare trois éléments :
| Élément | Rôle |
|---|---|
Configuration .tf | Ce qui est demandé dans le code |
| State Terraform | Ce que Terraform pense gérer |
| État réel | Ce qui existe réellement dans Docker |
Une dérive apparaît quand l’état réel ne correspond plus à ce qui est décrit dans la configuration Terraform.
Prérequis
Section intitulée « Prérequis »- Terraform installé
- Docker installé et lancé
- Un terminal et un éditeur de code
Vérifier :
terraform versiondocker versionArborescence
Section intitulée « Arborescence »tp-terraform-drift/├── main.tf├── variables.tf├── outputs.tf└── .gitignoreFichier .gitignore
Section intitulée « Fichier .gitignore ».terraform/*.tfstate*.tfstate.*.terraform.lock.hcl*.tfvarsFichier variables.tf
Section intitulée « Fichier variables.tf »variable "container_name" { description = "Nom du conteneur Docker" type = string default = "tp-drift-nginx"}
variable "image_name" { description = "Image Docker utilisée" type = string default = "nginx:latest"}
variable "external_port" { description = "Port exposé sur la machine locale" type = number default = 8080}Fichier main.tf
Section intitulée « Fichier main.tf »terraform { required_providers { docker = { source = "kreuzwerker/docker" version = "~> 3.0" } }}
provider "docker" {}
resource "docker_image" "nginx" { name = var.image_name}
resource "docker_container" "web" { name = var.container_name image = docker_image.nginx.image_id
ports { internal = 80 external = var.external_port }}Fichier outputs.tf
Section intitulée « Fichier outputs.tf »output "container_name" { description = "Nom du conteneur Docker" value = docker_container.web.name}
output "application_url" { description = "URL locale de l'application" value = "http://localhost:${var.external_port}"}Étape 1 : initialiser Terraform
Section intitulée « Étape 1 : initialiser Terraform »terraform initÉtape 2 : vérifier la configuration
Section intitulée « Étape 2 : vérifier la configuration »terraform fmtterraform validateÉtape 3 : créer le conteneur
Section intitulée « Étape 3 : créer le conteneur »terraform planterraform applyConfirmer avec :
yesTester :
curl http://localhost:8080Vérifier avec Docker :
docker psLe conteneur tp-drift-nginx doit apparaître.
Étape 4 : observer le state Terraform
Section intitulée « Étape 4 : observer le state Terraform »Lister les ressources suivies par Terraform :
terraform state listRésultat attendu :
docker_container.webdocker_image.nginxAfficher le détail du conteneur :
terraform state show docker_container.webÉtape 5 : première dérive : arrêter le conteneur manuellement
Section intitulée « Étape 5 : première dérive : arrêter le conteneur manuellement »Arrêter le conteneur sans passer par Terraform :
docker stop tp-drift-nginxVérifier : le conteneur est arrêté mais existe toujours :
docker ps # conteneur absentdocker ps -a # conteneur visible avec le statut ExitedPuis lancer :
terraform planComportement attendu : le provider
kreuzwerker/dockerne suit pas l’état running/stopped d’un conteneur : uniquement son existence. Terraform peut donc afficherNo changesmême si le conteneur est arrêté. C’est une limite du provider Docker, pas un bug Terraform.C’est un exemple de ce que Terraform ne détecte pas forcément : un arrêt manuel n’est pas une dérive visible dans le state si le provider ne modélise pas cet attribut.
Supprimer le conteneur arrêté pour continuer le TP :
docker rm tp-drift-nginxterraform applyÉtape 6 : deuxième dérive : supprimer le conteneur manuellement
Section intitulée « Étape 6 : deuxième dérive : supprimer le conteneur manuellement »Supprimer le conteneur hors Terraform :
docker rm -f tp-drift-nginxPuis lancer :
terraform planCette fois, Terraform détecte que la ressource docker_container.web n’existe plus réellement et propose de la recréer (+ create).
Appliquer :
terraform applyVérifier :
docker psC’est la dérive la plus simple et la plus courante : une ressource supprimée hors Terraform. Le state indique qu’elle existe, l’état réel dit qu’elle n’existe pas : Terraform la recrée.
Étape 7 : troisième dérive : remplacer le conteneur par un autre
Section intitulée « Étape 7 : troisième dérive : remplacer le conteneur par un autre »Supprimer le conteneur Terraform :
docker rm -f tp-drift-nginxCréer un conteneur manuel avec le même nom mais une autre image :
docker run -d --name tp-drift-nginx -p 8080:80 httpd:latestPuis exécuter :
terraform planTerraform compare son state (qui décrit un conteneur nginx:latest) avec ce qui existe réellement (un conteneur httpd:latest). Il doit proposer un remplacement ou une modification.
Attention lors de l’
apply: Terraform va tenter de supprimer le conteneur existant avant d’en créer un nouveau. S’il ne parvient pas à supprimer le conteneur manuel (permissions, etc.), l’applyéchouera. Le comportement est normal : Terraform reprend le contrôle de la ressource.
Appliquer pour rétablir l’état attendu :
terraform applyÉtape 8 : ressource créée hors Terraform
Section intitulée « Étape 8 : ressource créée hors Terraform »Créer un conteneur totalement hors Terraform :
docker run -d --name manuel-nginx -p 8090:80 nginx:latestPuis lancer :
terraform planTerraform ne propose pas de supprimer manuel-nginx : ce conteneur n’est pas dans son state, il ne le connaît pas.
Point important : Terraform ne gère que les ressources enregistrées dans son state. Une ressource créée hors Terraform est invisible pour lui. Pour qu’il commence à la gérer, il faudrait utiliser
terraform import.
Nettoyer le conteneur manuel :
docker rm -f manuel-nginxÉtape 9 : utiliser terraform plan -refresh-only
Section intitulée « Étape 9 : utiliser terraform plan -refresh-only »Afficher uniquement les changements d’état détectés, sans planifier de modification d’infrastructure :
terraform plan -refresh-onlyAppliquer uniquement la mise à jour du state :
terraform apply -refresh-onlyCette option permet de synchroniser le state avec l’état réel sans modifier l’infrastructure. Utile pour diagnostiquer une dérive avant de décider quoi faire.
Note : la commande
terraform refreshexiste mais est dépréciée depuis Terraform 1.5. Préférer systématiquementterraform plan -refresh-onlyetterraform apply -refresh-only.
Étape 10 : corriger une dérive
Section intitulée « Étape 10 : corriger une dérive »Selon la situation, plusieurs approches sont possibles :
| Situation | Action recommandée |
|---|---|
| L’état réel a été modifié par erreur | terraform apply pour rétablir l’état décrit dans le code |
| L’état réel est désormais correct et le code doit s’y conformer | Modifier le code Terraform pour correspondre à la réalité, puis terraform apply -refresh-only |
| La ressource ne doit plus être gérée par Terraform (sans la supprimer) | terraform state rm <ressource> : supprime la ressource du state uniquement, pas de l’infrastructure |
| Une ressource existante doit être prise en charge par Terraform | terraform import <ressource> <id> |
terraform state rmretire une ressource du state Terraform sans la détruire dans l’infrastructure. Après cette commande, Terraform ne la gère plus. À utiliser avec précaution car unterraform applyultérieur pourrait tenter de recréer la ressource.
Exercice 1 : dérive sur le port
Section intitulée « Exercice 1 : dérive sur le port »Provoquer une dérive de port sans modifier variables.tf : utiliser -var :
terraform plan -var="external_port=8081"Observer si Terraform propose une modification ou un remplacement du conteneur.
Appliquer pour voir le comportement réel :
terraform apply -var="external_port=8081"Rétablir le port initial :
terraform applyExercice 2 : dérive sur l’image
Section intitulée « Exercice 2 : dérive sur l’image »Provoquer une dérive d’image :
terraform plan -var="image_name=httpd:latest"terraform apply -var="image_name=httpd:latest"Observer comment Terraform traite le changement d’image : destruction et recréation du conteneur, ou modification en place ?
Rétablir l’image initiale :
terraform applyExercice 3 : comparer plusieurs commandes
Section intitulée « Exercice 3 : comparer plusieurs commandes »Tester les commandes suivantes dans différents scénarios de dérive :
terraform planterraform plan -refresh-onlyterraform applyterraform apply -refresh-onlyterraform state listterraform state show docker_container.webObserver les différences de comportement selon l’état réel du conteneur.
Nettoyage
Section intitulée « Nettoyage »terraform destroyConfirmer avec :
yesVérifier qu’il ne reste aucun conteneur ou volume résiduel :
docker ps -adocker volume ls