lesson ── terraform-beginner ── ~10 мин ── 4 шагов
В реальной работе HCL меняется постоянно: добавили тег, поправили имя, поменяли class у БД. Terraform должен понимать, что изменилось, и применить нужный набор API-вызовов, без удаления-создания всего подряд.
В этом уроке создадим бакет, поменяем у него теги и увидим как plan показывает diff. Узнаем разницу между «обновить» (update-in-place) и «пересоздать» (-/+ replacement).
интерактивный 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-update-${random_id.suffix.hex}" tags = {Owner = "student"
}
}
resource "random_id" "suffix" {byte_length = 4
}
Запусти:
cd /home/student/tf-update
terraform init -input=false
terraform apply -auto-approve -input=false
После apply state знает бакет с одним тегом Owner.
Если что-то падает: проверь init. И что LocalStack живой.
✓ Бакет создан с тегом Owner=student. Теперь добавим второй тег.
Открой main.tf и поменяй блок tags:
tags = {Owner = "student"
Environment = "learning"
}
Теперь сделай plan без apply, увидишь diff:
terraform plan
В выводе будет блок типа:
~ resource "aws_s3_bucket" "demo" { ~ tags = {"Owner" = "student"
+ "Environment" = "learning"
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
Знак ~ рядом с resource = «обновить в месте». Никакого пересоздания.
Внутри: + "Environment" = новый тег добавится. Owner без знака
См. tf-plan про значения знаков.
Если plan показал `-/+ resource ...`: значит, ты поменял что-то, что нельзя обновить без replacement. Откати и поменяй только tags.
✓ Plan показал ~ change. Применим: обновится без пересоздания.
terraform apply -auto-approve
Apply покажет:
aws_s3_bucket.demo: Modifying...
aws_s3_bucket.demo: Modifications complete after Xs
Apply complete! Resources: 0 added, 1 changed, 0 destroyed.
Ключевое: 0 destroyed, 1 changed. Бакет не пересоздавался. AWS-провайдер просто отправил PutBucketTagging API-запрос.
Объекты внутри (если бы были) остались на месте.
Это и есть update-in-place. Ваша задача, структурировать HCL так, чтобы большинство изменений шли по этому пути.
Если получаешь destroy: значит, кроме tags поменялось что-то ещё. Проверь главные поля (bucket, etc): они не должны меняться.
✓ Тег обновлён в месте, бакет тот же.
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 для полной матрицы.
Главный инвариант Terraform: после apply повторный plan = «No changes». Если показывает изменения, что-то не так (drift или ignore_changes пропустил что-то).
Проверим:
terraform plan -detailed-exitcode
echo "exit: $?"
Должно быть exit: 0. Если бы там было 2, значит, есть
несогласованность.
-detailed-exitcode важен для CI: можно автоматически алертить
при drift'е.
Если plan показывает «No changes» в человекочитаемом тексте: значит, всё ОК, exit будет 0.
✓ Plan чистый. Invariant соблюдён: state == HCL.
Некоторые атрибуты ресурса нельзя поменять без пересоздания.
Например, availability_zone у EC2-инстанса, instance_class
у части RDS-инстансов, bucket у S3-бакета, если меняешь имя
бакета, AWS не умеет «переименовать», только создать новый и
снести старый. Terraform покажет это в plan'е как -/+.
Будь осторожен: данные пересоздаваемого ресурса теряются.
Ты увидел четыре типа изменений в plan: + создать, ~ обновить
в месте, -/+ пересоздать, и финальное No changes после apply.
Это базовая грамматика чтения plan'ов.
команды
terraform planпоказать diff между HCL и stateterraform apply -auto-approveприменить планterraform plan -detailed-exitcodeexit 0 = чисто, 2 = есть измененияконцепции