open atlas
↑ К треку
AWS на практике AWS · 06 · 02

Terraform на AWS: провайдеры, state и remote backend

Terraform — облачно-агностичный IaC на HCL: AWS-провайдер маппит ресурсы на API AWS, но, в отличие от CloudFormation, state-файлом владеешь ты. Освой remote backend, locking и чтение plan — иначе порча state и тихий replace возьмут верх над тобой.

AWS Senior ◷ 20 min
Уровень
ОсновыJuniorMiddleSenior

Два инженера запускают terraform apply против одного конфига в одну и ту же минуту. Lock нет, потому что state лежит в одном S3-бакете с выключенным locking «чтобы было проще». Оба чтения видят одно стартовое состояние; оба записи гонятся перезаписать объект. Вторая запись побеждает, только что созданный первым инженером NAT-шлюз теперь сирота, больше не отслеживаемый в state, а счётчик serial в state-файле рассинхронизирован с реальностью. Следующий apply пытается «создать» ресурсы, которые уже существуют, и падает на дублирующихся именах — а неотслеживаемый NAT-шлюз тихо набегает на $32 в месяц, которые никто не найдёт до отчёта по затратам. С CloudFormation этот класс багов почти невозможен: AWS держит state стека на своей стороне и сериализует изменения. Terraform отдал тебе эту ответственность, а ты её пропустил.

Провайдеры: HCL поверх API любого облака

С CloudFormation и CDK ты познакомился в предыдущем уроке — это AWS-нативные инструменты, где AWS парсит твой шаблон и отслеживает стек за тебя. Terraform от HashiCorp делает другую ставку: один инструмент, один язык (HCL, HashiCorp Configuration Language) на все облака. Мост к каждой платформе — провайдер, плагин, который маппит HCL-блоки ресурсов на вызовы API конкретного вендора. Провайдер aws превращает блок aws_instance в вызовы EC2 RunInstances; провайдер cloudflare или google делает то же для своих API. Один конфиг может объявлять ресурсы сразу через несколько провайдеров — в этом весь смысл: мульти-облачное или мульти-вендорное хозяйство, описанное одним языком и одним workflow.

Ты объявляешь провайдер и ресурс, и это и есть единица работы. Блок ниже фиксирует версию AWS-провайдера, задаёт регион и просит бакет:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "eu-central-1"
}

resource "aws_s3_bucket" "assets" {
  bucket = "acme-prod-assets"
  tags   = { Team = "platform" }
}

Ограничение версии ~> 5.0 значит больше, чем кажется: провайдеры выкатывают ломающие изменения, и незафиксированный провайдер может переписать половину твоего plan после несвязанного апгрейда. Фиксируй его так же, как фиксируешь transform в CloudFormation.

State: то, что CloudFormation прячет, а Terraform отдаёт тебе

Вот определяющее различие уровня senior. Когда ты делаешь apply, Terraform пишет state-файл, который записывает связки между объектами в реальном облаке и инстансами ресурсов в твоём конфиге — фактические ID ресурсов, атрибуты и метаданные зависимостей. На следующем запуске Terraform читает этот state, обновляет (refresh) его против живого API, чтобы обнаружить drift (реальный мир расходится с тем, во что верит state), вычисляет разницу с твоим конфигом и планирует только дельту. State и есть память Terraform; без него инструмент не отличит «create» от «update».

У CloudFormation такая же память, но AWS держит её на своей стороне, и ты её не трогаешь. Terraform делает её файлом, за который ты отвечаешь, — и у этой ответственности острые края:

  • Локальный state опасен для команд. terraform.tfstate на одном ноутбуке нельзя расшарить, он теряется, если ноутбук умрёт, и ничего не сериализует — двое не могут безопасно работать вместе.
  • State может содержать секреты. Пароль RDS или сгенерированный ключ попадает в state открытым текстом. Коммит state в git его утекает; backend обязан шифровать его в покое.
  • Никогда не правь state руками. Это производный индекс, а не исходник. Ручная правка рассинхронизирует его с реальностью; используй сабкоманды terraform state или terraform import, чтобы взять существующий ресурс под управление.

Все три правила сводятся к одному принципу: относись к state как к общей, зашифрованной, блокируемой базе данных — потому что именно этим он и является. Пропусти любое из них, и ты на один параллельный apply или на один git push от утечки учёток или потери ресурсов.

Remote backend и state locking

Фикс для всех опасностей state — remote backend. S3-backend хранит объект state в S3-бакете (bucket + key + region), чтобы вся команда читала и писала одну общую долговечную копию, и шифрует этот state в покое. Вторая половина — state locking: перед изменением state Terraform берёт lock, так что параллельный apply обязан ждать, а не гнаться. Исторически ты задавал таблицу DynamoDB (partition key с именем LockID) через dynamodb_table; этот путь ещё работает, но теперь deprecated в пользу S3-native locking — задай use_lockfile = true, и Terraform пишет объект tflock рядом со state для координации, без отдельной таблицы.

terraform {
  backend "s3" {
    bucket       = "acme-tf-state"
    key          = "prod/network/terraform.tfstate"
    region       = "eu-central-1"
    encrypt      = true
    use_lockfile = true
  }
}

С этим гонка из Hook невозможна: apply второго инженера блокируется на локе, пока первый не закончит и не отпустит его. Это та конфигурация, которую команда «чтобы было проще» пропустила.

АспектCloudFormation / CDKTerraform
Охват облаковТолько AWSМульти-облако через провайдеры
Владение stateУправляется AWS, на сервереState-файлом владеешь ты
Безопасность параллелизмаСериализуется AWSLocking настраиваешь ты
НаписаниеYAML/JSON (CFN) или реальный язык (CDK)DSL HCL
Секреты в stateСкрыты AWSВ state; backend надо шифровать

Чтение plan и модули

terraform plan — это предохранитель, и чтение его — навык уровня senior. Он печатает diff с четырьмя действиями: + создать, - удалить, ~ обновить на месте и -/+ replace — удалить, затем создать заново. Последний символ — опасный. Поле, которое нельзя изменить на месте (переименование идентификатора БД, смена неизменяемого атрибута), вынуждает replace, а replace базы данных значит, что её уничтожают и создают свежую пустую. Plan говорит тебе об этом простым текстом — -/+ destroy and then create replacement — и инженер, который применяет, не прочитав, теряет данные. Всегда читай plan перед apply; это и есть вся причина, по которой plan — отдельная команда.

terraform init        # скачать провайдеры, настроить backend
terraform plan        # обновить state, показать diff create/update/replace/destroy
terraform apply       # взять lock, выполнить, записать state обратно

Последний строительный блок — модули, переиспользуемые параметризованные наборы ресурсов, подтягиваемые из публичного реестра или локального пути, чтобы ты написал VPC один раз и вызывал его по окружениям, а не копипастил HCL. Модули — то, как кодовая база Terraform остаётся DRY на масштабе.

Почему это работает

Почему «ты владеешь state» — фича, а не просто бремя? Потому что state-файл — это ещё и портируемая, инспектируемая запись всего твоего хозяйства, не привязанная к control plane одного вендора. Ты можешь через terraform import взять существующие руками собранные ресурсы под управление, рефакторить через провайдеры и запускать ровно тот же workflow, лежит ли ресурс в AWS, Cloudflare или SaaS-API. Серверный state CloudFormation безопаснее по умолчанию, но говорит он только на AWS. State-файл — это и цена, и механизм портируемости Terraform.

Выбери лучший вариант

Команда держит prod через AWS, Cloudflare и Postgres-SaaS. Платформенные инженеры свободно владеют HCL, спокойно владеют remote backend и хотят один инструмент и один workflow на всех трёх вендоров. Выбери IaC.

Викторина

Какое ключевое операционное различие между Terraform и CloudFormation порождает большинство специфичных для Terraform сбоев?

Викторина

Plan показывает `-/+ aws_db_instance.primary (destroy and then create replacement)`. Что делать?

Вспомните перед уходом
  1. 01
    Почему state-файл Terraform — центральное понятие, и какие три правила накладывает владение им?
  2. 02
    Что даёт remote backend с locking и как безопасно читать plan?
Итог

Terraform — облачно-агностичный IaC от HashiCorp, написанный на HCL, где плагин-провайдер маппит блоки ресурсов на API вендора — провайдер aws на AWS, другие на Cloudflare, Google и SaaS-API — так что один конфиг и один workflow охватывают несколько облаков. Определяющее на уровне senior отличие от CloudFormation и CDK, с которыми ты познакомился в предыдущем уроке, — это state: Terraform пишет state-файл, маппящий твой конфиг на реальные ID ресурсов, обновляет его для обнаружения drift и планирует дельту, тогда как AWS держит этот state на сервере за тебя. Владение state накладывает три правила — не используй локальный state для команд, шифруй backend, потому что state может держать секреты, и никогда не правь state руками (используй terraform import, чтобы брать существующие ресурсы под управление). Фикс — это remote backend, обычно S3 (bucket + key + region, шифрованный), плюс state locking через таблицу DynamoDB с LockID или более новый S3-native use_lockfile, который сериализует параллельные apply и предотвращает гонку порчи. Workflow — написать HCL, terraform plan, затем terraform apply, и чтение plan необсуждаемо: + создаёт, - удаляет, ~ обновляет на месте, а -/+ заменяет — удалить и создать заново, что для stateful-ресурса значит потерю данных. Модули держат большие кодовые базы DRY. Правило выбора простое: тянись к Terraform, когда ты мульти-облачный или хочешь один инструмент на провайдеров и принимаешь управление state; тянись к CloudFormation или CDK, когда ты целиком на AWS и хочешь, чтобы state вёл за тебя AWS. Теперь, когда откроешь новый Terraform-репозиторий и увидишь terraform.tfstate рядом с .tf-файлами без конфига backend — ты будешь знать, что нужно исправить, прежде чем кто-то другой это тронет.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources4
expand
  1. 01
  2. 02
  3. 03
  4. 04

Trademarks belong to their respective owners. Editorial reference only.