Зачем нужны точечные операции
По умолчанию Terraform работает со всем проектом разом: один plan показывает все изменения, один apply их применяет. Но иногда нужно что-то конкретное:
- Пересоздать один сломанный ресурс, не трогая остальное.
- Применить только часть конфигурации, чтобы не цеплять unrelated изменения.
- Обойти временный bag в провайдере на одном ресурсе.
Для этого, -replace и -target.
-replace=<address>, пересоздать ресурс
Заставляет Terraform добавить в plan действие «destroy + create» даже если код не менялся. Полезно когда ресурс в облаке сломался (повреждённый EC2, зависший cache), а HCL правильный.
terraform apply -replace=aws_instance.web
Plan покажет:
# aws_instance.web will be replaced, as requested
-/+ resource "aws_instance" "web" {...
}
Plan: 1 to add, 0 to change, 1 to destroy.
Это замена устаревшего terraform taint. До TF 0.15.2 надо было
делать terraform taint aws_instance.web; terraform apply, два
шага и модификация state руками. Теперь, один флаг.
Адресация для -replace
Поддерживается полная адресация:
# обычный ресурс
terraform apply -replace=aws_s3_bucket.demo
# элемент count
terraform apply -replace='aws_instance.web[0]'
# элемент for_each
terraform apply -replace='aws_s3_bucket.regional["eu"]'
# ресурс внутри модуля
terraform apply -replace='module.networking.aws_vpc.main'
Заметьте кавычки в shell, [, ], " shell интерпретирует. Без
кавычек, ошибка.
Несколько -replace
Можно указывать несколько раз, будут пересозданы все:
terraform apply \
-replace=aws_instance.web \
-replace=aws_db_instance.main
-target=<address>, применить только указанный
Игнорирует ВСЁ кроме указанного ресурса (и его зависимостей):
terraform apply -target=aws_s3_bucket.logs
Plan:
Warning: Resource targeting is in effect
You are creating a plan with the -target option, which means that
the result of this plan may not represent all of the changes
requested by the current configuration.
# aws_s3_bucket.logs will be created
+ resource "aws_s3_bucket" "logs" {...
}
Terraform сам предупреждает что это плохо. Это не повседневный инструмент, это аварийный.
Когда -target оправдан
- Срочно нужно создать/изменить один ресурс, а другие ломают plan.
- Тестируете один модуль в большом проекте.
- Bootstrap нового окружения по частям (сначала VPC, потом всё остальное).
- Разбор циклической зависимости через временное удаление одной стороны.
Когда -target, плохая идея
- Регулярная работа. Если используете каждый день, что-то не так с структурой проекта. Лучше разбить на отдельные state-файлы.
- В CI/CD. Не должно быть автоматизации, которая зависит от -target.
- Чтобы «обойти» drift вместо его починки.
- Для прода без явного incident-флага. Любой -target в проде, это отклонение от нормы, должно быть в runbook.
Почему -target плох (по версии HashiCorp)
Из docs Terraform:
Targeting is a powerful but disruptive feature, and so should be used only in exceptional circumstances.
Конкретно:
-
Создаёт частично-консистентный state. После
-targetstate и реальность в облаке отличаются от того, что описано в HCL. Может быть так часами, если забыли потом сделать «полный apply». -
Скрывает реальные зависимости. Если ресурс A неявно зависит от B через переменную или data,
-target=Aлибо упадёт, либо втянет B неожиданно. -
Усложняет debugging. «Почему ALB не работает?», потому что полтора месяца назад кто-то сделал
-target=albи не применил обновления security_group.
Поэтому HashiCorp намеренно не убирают warning. Каждый раз напоминает что вы делаете что-то нестандартное.
-target с зависимостями
Если ресурс ссылается на другие, они тоже будут затронуты:
resource "aws_vpc" "main" { ... }resource "aws_subnet" "private" {vpc_id = aws_vpc.main.id
}
terraform apply -target=aws_subnet.private
Применит и subnet, и VPC (потому что subnet зависит от VPC). Это
делает -target чуть менее опасным, нельзя сослаться на
несуществующее.
Чем НЕ являются эти флаги
-replace≠ destroy + create вручную. Это атомарная операция в одном apply, со всеми зависимостями.-target≠ workspace. Workspace, это отдельный state с тем же HCL. Target, кусок одного state.-target≠ модуль.module.networkingчерез -target, это весь модуль, не «только networking», но не «изоляция модуля».
Подводные камни
-
-targetпринимается через запятую тоже:-target=A -target=B, не-target=A,B. Если хотите много, повторяйте флаг. -
-replaceне работает на data-блоках. Data, это read-only, его нечего пересоздавать. Если хочется «перечитать», следующий plan/apply сам обновит data. -
После
-targetобязательно сделайте полный apply. Иначе забудете и расхождение state и HCL останется навсегда. Привычка:apply -target=X && applyв одном скрипте. -
-replaceпомечает только в plan'е. Сам state не меняется до apply. Если plan показался плохим, просто не делайте apply, ничего не сломается. -
-targetне работает сimportблоком. Декларативный import из TF 1.5+ применяется к всему конфигу.