Terraform 22: El bloque lifecycle
easy⏱ 5 mincourseterraform
create_before_destroy
Por defecto Terraform destruye y luego crea al reemplazar — una ventana de downtime. create_before_destroy = true invierte el orden: levanta el reemplazo primero y después elimina el viejo. Esencial para cosas que nunca deben desaparecer del todo, como un VM scale set o una IP pública con tráfico.
resource "azurerm_public_ip" "ingress" {
name = "orders-ingress-pip"
resource_group_name = azurerm_resource_group.main.name
location = "westus2"
allocation_method = "Static"
lifecycle {
create_before_destroy = true # new IP is up before the old is freed
}
}
prevent_destroy e ignore_changes
prevent_destroy = true hace que cualquier plan que borre el recurso falle — un cinturón de seguridad para stores de estado, bases de datos de prod, key vaults. ignore_changes = [ ... ] le dice a Terraform que deje de gestionar ciertos atributos después de crear, para que cambios externos (instancias que fija el autoscaler, un secreto rotado) no aparezcan como drift en cada plan.
resource "azurerm_storage_account" "tfstate" {
name = "myorgtfstatedev"
resource_group_name = azurerm_resource_group.main.name
location = "westus2"
account_tier = "Standard"
account_replication_type = "LRS"
lifecycle {
prevent_destroy = true # never let a plan delete the state store
ignore_changes = [tags] # tags are managed elsewhere
}
}
resource "azurerm_linux_virtual_machine_scale_set" "agents" {
name = "ci-agents-vmss"
resource_group_name = azurerm_resource_group.main.name
location = "westus2"
sku = "Standard_D2s_v5"
instances = 2
lifecycle {
ignore_changes = [instances] # autoscaler owns the instance count
}
}
Los valores de lifecycle deben ser literales
El bloque lifecycle se lee muy temprano, así que sus argumentos deben ser literales estáticos — no podés calcular prevent_destroy desde una variable ni referenciar otros recursos. ignore_changes recibe una lista de nombres de atributos (referencias simples como tags, instances), no strings. Recurrí a esto solo cuando un plan por defecto haría algo indebido.
Modelá un planificador consciente del lifecycle
Escribí planChange({ preventDestroy, ignoreChanges, changedAttrs, willDestroy }). Si willDestroy y preventDestroy → devolvé "error: prevent_destroy". Si no, descartá los changedAttrs que estén en ignoreChanges; si no queda ninguno → "no-op", si no "update". Llamala con ignoreChanges: ["instances"], changedAttrs: ["instances"], willDestroy: false y logueá el resultado (esperado no-op).