lesson ── terraform-beginner ── ~12 мин ── 4 шагов
По умолчанию Terraform работает так: «если в HCL стало по-другому,
изменить ресурс. Если убрал из HCL, удалить». Но иногда поведение
надо подкрутить. Для этого есть блок lifecycle внутри ресурса.
В этом уроке ты попробуешь три опции: prevent_destroy (защита от
удаления), ignore_changes (игнор drift'а по атрибутам),
create_before_destroy (zero-downtime пересоздание). См.
tf-resource-lifecycle.
интерактивный sandbox
Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.
stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя
Создай main.tf:
resource "aws_s3_bucket" "demo" { bucket = "linuxlab-lifecycle-${random_id.suffix.hex}" tags = {Owner = "student"
LastTouched = "2026-01-01" # это поле часто меняется снаружи
}
}
resource "random_id" "suffix" {byte_length = 4
}
cd /home/student/tf-lifecycle
terraform init -input=false
terraform apply -auto-approve -input=false
Это базовый setup: следующие шаги будут только добавлять lifecycle опции.
✓ Бакет создан с двумя тегами. Дальше: защита от destroy.
Добавь блок lifecycle в ресурс:
resource "aws_s3_bucket" "demo" { bucket = "linuxlab-lifecycle-${random_id.suffix.hex}" tags = {Owner = "student"
LastTouched = "2026-01-01"
}
lifecycle {prevent_destroy = true
}
}
Применить:
terraform apply -auto-approve
Теперь попробуй удалить:
terraform destroy -auto-approve
Получишь:
Error: Instance cannot be destroyed
Resource aws_s3_bucket.demo has lifecycle.prevent_destroy set...
Защита работает: чтобы реально снести, нужно сначала убрать
prevent_destroy, сделать apply, и только тогда destroy. Это
двухшаговая защита от случайностей.
Если destroy прошёл без ошибки: значит, apply не успел записать lifecycle в state. Повтори apply и destroy.
✓ prevent_destroy блокирует destroy. В проде это спасает от опечаток.
Представь: внешний скрипт обновляет тег LastTouched каждую ночь.
Terraform будет видеть это как drift и каждый plan показывать
изменение. Раздражает и опасно.
Решение, ignore_changes. Добавь в lifecycle:
lifecycle {prevent_destroy = true
ignore_changes = [
tags["LastTouched"],
]
}
Применить:
terraform apply -auto-approve
Теперь имитируем drift, поменяй тег через AWS CLI (точнее, его эмуляцию в LocalStack эмулирует aws-сlient внутри). Но в нашем sandbox мы можем сделать иначе: поменять значение в HCL.
Открой main.tf, поменяй:
LastTouched = "2026-06-15" # новая дата
И запусти plan:
terraform plan
Вывод: No changes. Terraform увидел разницу в
tags["LastTouched"], но ignore_changes сказал «не считай это
изменением». State и реальность считаются совпавшими.
Если plan показывает изменение: проверь синтаксис ignore_changes: список квадратных скобок, имена в [].
✓ ignore_changes работает: drift по конкретному атрибуту игнорируется.
Третья частая опция, create_before_destroy = true. Она меняет порядок при пересоздании ресурса (когда атрибут требует replacement): по умолчанию Terraform сначала сносит старый, потом создаёт новый, между ними даунтайм. С create_before_destroy наоборот: сначала создать новый, переключить зависимости, потом снести старый. Это даёт zero-downtime, но требует уникальности имён (нельзя два ресурса с одинаковым identifier одновременно).
Чтобы оставить sandbox чистым (хотя он и так умрёт по TTL), убери lifecycle и снеси бакет:
resource "aws_s3_bucket" "demo" { bucket = "linuxlab-lifecycle-${random_id.suffix.hex}" tags = {Owner = "student"
}
# никакого lifecycle
}
terraform apply -auto-approve
terraform destroy -auto-approve
Бакет снесён. Это и есть правильный workflow:
prevent_destroy через apply.Двухшаговая последовательность, не лишняя бюрократия, это защита от случайностей.
Если apply ругается на удаление lifecycle: это значит prevent_destroy всё ещё в state. Сделай apply сначала, потом destroy.
✓ Всё снесено. Lifecycle ты теперь умеешь использовать осмысленно.
OpenTofu держит CLI и state совместимыми с Terraform по командам
этого шага: миграция обычно проходит через mv .terraform .terraform.bak; tofu init -upgrade. Но при первом переходе
сделай backup state и прогон на feature-branch - расхождения
концентрируются в новых фичах (variables в backend,
state-encryption, OCI registry-backed модули). См.
tf-opentofu-parity для полной матрицы.
Ты увидел три типичных применения lifecycle: блокировка
destroy через prevent_destroy, игнор тегов через
ignore_changes, и понимание того, как
create_before_destroy меняет порядок операций при
пересоздании.
команды
terraform planlifecycle покажет ошибку если защита нарушенаterraform state show <addr>увидеть какие lifecycle активны на ресурсеконцепции