Зачем нужен plan
terraform plan, это примерка. Вы пишете HCL: «хочу один бакет с тегами». Terraform смотрит, что уже создано (это записано в state-файле), и показывает разницу: «нужно создать один новый бакет, изменений и удалений нет».
Главное: plan ничего не меняет. Он не звонит в AWS с командой «создай». Он только смотрит и сравнивает. Это безопасная команда, её можно запускать сколько угодно раз.
Что показывает plan
Допустим, вы написали:
resource "aws_s3_bucket" "demo" {bucket = "my-bucket-12345"
tags = {Owner = "student"
}
}
И запустили terraform plan. Вывод примерно такой:
Terraform will perform the following actions:
# aws_s3_bucket.demo will be created
+ resource "aws_s3_bucket" "demo" {+ bucket = "my-bucket-12345"
+ id = (known after apply)
+ tags = {+ "Owner" = "student"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Разбор:
+ resource ..., этот ресурс будет создан. Знак+= добавить.+ bucket = "my-bucket-12345", значение, которое Terraform отправит в API.+ id = (known after apply), атрибут появится только после создания, сейчас его не знаем.Plan: 1 to add, 0 to change, 0 to destroy, итоговая сводка. Это самая важная строчка.
Знаки в diff'е (запомните)
| Знак | Что значит |
|---|---|
+ | Создать новый ресурс или атрибут |
- | Удалить ресурс или атрибут |
~ | Изменить значение (можно сделать без пересоздания) |
-/+ | Удалить и создать заново (force replacement) |
Самый опасный, -/+. Он значит «ресурс нужно пересоздать с нуля». Если это база данных, данные пропадут. Если EC2, потеряете IP-адрес. Всегда вчитывайтесь в строки с -/+.
Exit code: 0, 1, 2
По умолчанию terraform plan всегда возвращает exit code 0, даже если есть изменения. Это удобно для CI: команда не падает.
Но если запустить с флагом -detailed-exitcode, появляется новая логика:
0, изменений нет, state == HCL. «No changes».1, ошибка (синтаксис, провайдер не отвечает, токен невалиден).2, план есть, изменения требуются.
terraform plan -detailed-exitcode
echo $? # 0, 1 или 2
Это незаменимо в скриптах: «если есть drift, пришли мне алерт».
Сохранение плана в файл
plan можно сохранить и потом применить ровно его (без пересчёта):
terraform plan -out=tfplan.bin # сохранили
terraform apply tfplan.bin # применяем именно этот план
Зачем так делают:
- В CI: ревьюер видит plan в PR, мержит, и apply применяет ровно то, что было показано. Между показом и применением никакой код не успеет «подсунуться».
tfplan.binможет содержать секреты (если они в state). Не коммитьте его в git.
Подводные камни
-
«No changes», это инвариант, к которому надо стремиться после apply. Если сразу после
applyповторныйplanпоказывает изменения, значит, у вас drift (что-то изменилось вне Terraform), или ваш HCL не отражает реальность. Это плохой признак. -
Plan читает state, а не реальный AWS. Если кто-то руками удалил бакет в консоли, plan этого не заметит, пока не сделаете
terraform refreshилиterraform plan -refresh=true(это default, но иногда отключают). См. tf-state. -
Plan может выполняться долго. На больших проектах (тысячи ресурсов) plan может занимать минуты. Terraform опрашивает облако про каждый. Это нормально. Если очень больно,
-target=resource.nameдля точечного плана. -
Plan не предсказывает всё. Некоторые атрибуты вычисляются на стороне облака. Plan покажет
(known after apply), это нормально, это не «секрет», просто значение появится после создания. -
-targetиспользовать редко. Это «костыль для непредвиденных ситуаций». Регулярное использование-target, признак, что ваш HCL неправильно структурирован.