Aller au contenu
Infrastructure as Code medium
🔐 Alerte sécurité — Incident supply chain Trivy : lire mon analyse de l'attaque

lifecycle Terraform : maîtriser le cycle de vie des ressources

12 min de lecture

logo terraform

Votre terraform apply détruit et recrée votre base de données à chaque changement de version d’image — avec une coupure de service à la clé. Ou vous lancez terraform destroy par erreur et perdez un volume de données critique faute de protection.

Le bloc lifecycle existe pour contrôler précisément ces comportements. Par défaut, Terraform détruit une ressource avant d’en créer une nouvelle lorsqu’il doit la remplacer. Pour certaines ressources critiques — bases de données, volumes persistants, certificats — ce comportement est inacceptable. create_before_destroy l’inverse. prevent_destroy bloque toute destruction accidentelle, même un terraform destroy explicite. ignore_changes permet d’exclure des attributs qui changent hors de Terraform (taille de disque redimensionné manuellement, tags ajoutés par une autre équipe). Ces trois options couvrent la grande majorité des cas rencontrés en production.

  • create_before_destroy : inverser l’ordre destruction/création
  • prevent_destroy : bloquer toute destruction accidentelle
  • ignore_changes : ignorer certains attributs lors des plans
  • replace_triggered_by : forcer le remplacement sur changement externe
  • Comportements réels capturés sur un lab KVM

Pensez aux phases d’une ressource dans un cycle de vie d’objet :

# Cycle de vie d'un objet
object.create()
object.update()
object.delete()

Par défaut, Terraform suit ce cycle : créer → mettre à jour → détruire. Mais pour certaines ressources critiques, ce cycle a des problèmes :

  • Une base de données détruite puis recrée = perte de données
  • Paramètre sensible modifié hors de Terraform devrait être ignoré
  • Service dépendant doit rester disponible pendant la mise à jour

Le bloc lifecycle permet de modifier ce cycle : créer avant de détruire l’ancienne version, bloquer complètement la destruction, ou ignorer certains changements.

resource "type" "nom" {
# ...attributs...
lifecycle {
create_before_destroy = true
prevent_destroy = false
ignore_changes = [attribut1, attribut2]
replace_triggered_by = [autre_ressource.nom]
}
}

Terraform remplace une ressource en faisant destroy → create. Pendant la destruction, la ressource n’existe plus. Pour des disques ou des bases de données, cette fenêtre est problématique.

resource "libvirt_volume" "base" {
name = "vm-base.qcow2"
pool = "default"
target = { format = { type = "qcow2" } }
create = { content = { url = var.image_path } }
lifecycle {
create_before_destroy = true
}
}

Ordre d’exécution avec create_before_destroy = true :

  1. Nouveau volume créé
  2. Ancienne référence mise à jour
  3. Ancien volume détruit

Protège une ressource contre toute destruction — que ce soit via terraform destroy ou via un plan qui remplacerait la ressource.

resource "libvirt_volume" "data" {
name = "vm-data.qcow2"
pool = "default"
capacity = 1
capacity_unit = "GiB"
target = { format = { type = "qcow2" } }
lifecycle {
prevent_destroy = true
}
}

Tentative de destruction de ce volume :

│ Error: Instance cannot be destroyed
│ on main.tf line 16:
│ 16: resource "libvirt_volume" "data" {
│ Resource libvirt_volume.data has lifecycle.prevent_destroy set, but the
│ plan calls for this resource to be destroyed. To avoid this error and
│ continue with the plan, either disable lifecycle.prevent_destroy or reduce
│ the scope of the plan using the -target option.

Terraform refuse le plan avant toute action. Pour détruire la ressource, il faut d’abord passer prevent_destroy = false et appliquer.

Certains attributs sont modifiés hors Terraform (l’opérateur change la RAM via virsh, un autoscaler modifie le nombre d’instances, etc.). Sans ignore_changes, le prochain terraform plan proposerait de remettre la valeur définie dans le code.

resource "libvirt_domain" "vm" {
name = "lab13-vm"
memory = var.memory # 512 MiB dans le code
memory_unit = "MiB"
vcpu = 1
# ...
lifecycle {
ignore_changes = [memory]
}
}

Avec memory=512 dans le state et memory=1024 dans la variable :

Fenêtre de terminal
terraform plan -var="memory=1024"
No changes. Your infrastructure matches the configuration.

Terraform ignore la différence sur memory. La VM n’est pas recréée.

lifecycle {
ignore_changes = all
}

Terraform ne planifie jamais de changements sur cette ressource après sa création. À utiliser avec beaucoup de précaution — les dérives ne seront plus détectées.

Force le remplacement d’une ressource quand une autre ressource ou attribut change — même si les propres attributs de la ressource n’ont pas changé.

resource "libvirt_volume" "config" {
name = "config-v2.qcow2"
# ...
}
resource "libvirt_domain" "vm" {
name = "lab13-vm"
memory = 512
# ...
lifecycle {
# Remplacer la VM si le volume de config est recréé
replace_triggered_by = [libvirt_volume.config]
}
}

Dès que libvirt_volume.config est recréé (remplacé), libvirt_domain.vm sera lui aussi remplacé au prochain apply.

# create_before_destroy sur le disque système
resource "libvirt_volume" "base" {
name = "${var.vm_name}-base.qcow2"
pool = "default"
target = { format = { type = "qcow2" } }
create = { content = { url = var.image_path } }
lifecycle {
create_before_destroy = true
}
}
# prevent_destroy sur le disque de données
resource "libvirt_volume" "data" {
name = "${var.vm_name}-data.qcow2"
pool = "default"
capacity = 1
capacity_unit = "GiB"
target = { format = { type = "qcow2" } }
lifecycle {
prevent_destroy = true
}
}
# VM avec ignore_changes sur memory
resource "libvirt_domain" "vm" {
name = var.vm_name
type = "kvm"
memory = var.memory
memory_unit = "MiB"
vcpu = 1
os = { type = "hvm", type_arch = "x86_64", type_machine = "q35" }
devices = {
disks = [
{ source = { file = { file = libvirt_volume.base.path } }
target = { dev = "vda", bus = "virtio" } },
{ source = { file = { file = libvirt_volume.data.path } }
target = { dev = "vdb", bus = "virtio" } }
]
interfaces = [{
model = { type = "virtio" }
source = { network = { network = "default" } }
}]
}
lifecycle {
ignore_changes = [memory]
}
depends_on = [libvirt_volume.base, libvirt_volume.data]
}

Résultats apply :

libvirt_volume.base: Creating...
libvirt_volume.data: Creating...
libvirt_volume.data: Creation complete after 0s
libvirt_volume.base: Creation complete after 1s
libvirt_domain.vm: Creating...
libvirt_domain.vm: Creation complete after 0s [name=lab13-vm]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
ArgumentEffetCas d’usage typique
create_before_destroyNouveau créé avant l’ancien détruitBases de données, LB, disques critiques
prevent_destroyRefuse tout plan qui détruirait la ressourceDonnées de production, volumes persistants
ignore_changesIgnore les diffs sur certains attributsRAM gérée par autoscaler, tags externes
replace_triggered_byRemplace la ressource si une dépendance changeVM à rebooter quand la config change
SymptômeCauseSolution
Instance cannot be destroyedprevent_destroy = true actifPasser à false, appliquer, puis détruire
Plan vide malgré une variable changéeignore_changes inclut cet attributVérifier la liste ignore_changes
create_before_destroy conflit de nomLe nouveau et l’ancien ont le même nomAjouter un suffixe de version dans le nom
  1. create_before_destroy inverse l’ordre destroy/create — essentiel pour les ressources sans downtime
  2. prevent_destroy est un garde-fou HCL — il bloque les plans Terraform, pas les suppressions directes
  3. ignore_changes = [attr] est utile quand un outil externe gère cet attribut
  4. replace_triggered_by lie le cycle de vie d’une ressource à une autre
  5. Ces arguments se combinent dans le même bloc lifecycle {}

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn