Terraform state: как не потерять инфраструктуру
Terraform state: как не потерять инфраструктуру
Terraform хранит всё своё знание об инфраструктуре в одном файле — terraform.tfstate. Пока вы работаете в одиночку и держите его локально, всё выглядит просто. Но стоит появиться второму инженеру или второму ноутбуку — и начинается хаос: конфликты, потерянные ресурсы, задвоенные машины. Разберёмся, как устроен state, почему он критичен и как правильно с ним работать в команде.
Что такое state и зачем он нужен
State — это снимок реального состояния вашей инфраструктуры с точки зрения Terraform. В нём записано, какие ресурсы были созданы, какие у них идентификаторы в облаке и какие зависимости между ними существуют. Без state Terraform не знает, что уже существует, и при каждом apply будет пытаться создать всё заново.
Файл terraform.tfstate — обычный JSON, но трогать его руками крайне не рекомендуется. Любое ручное редактирование может сломать соответствие между реальностью и тем, что думает Terraform.
Remote state: обязательно для команды
Локальный state — источник боли. Решение — remote backend. Самые популярные варианты:
- S3 + DynamoDB (AWS) — классика: файл в бакете, блокировка через DynamoDB
- Terraform Cloud / HCP Terraform — встроенное решение от HashiCorp
- GitLab-managed state — удобно, если вы уже на GitLab
- MinIO + DynamoDB-совместимый бэкенд — self-hosted альтернатива S3
Пример конфигурации backend на S3:
terraform {
backend "s3" {
bucket = "my-tf-state"
key = "prod/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Блокировки: защита от параллельных apply
Когда два инженера одновременно запускают terraform apply, без блокировок они перезапишут state друг друга. DynamoDB-таблица решает это через механизм pessimistic locking: первый apply захватывает замок, второй ждёт или получает ошибку.
Если apply упал и замок не снялся, используйте:
terraform force-unlock LOCK_ID
Делайте это осторожно — только убедившись, что параллельного apply нет.
Команды для работы со state
Несколько команд, которые должен знать каждый:
terraform state list— список всех ресурсов в stateterraform state show aws_instance.web— детали конкретного ресурсаterraform state mv— переименование или перемещение ресурса без пересозданияterraform state rm— удаление ресурса из state (сам ресурс в облаке остаётся)terraform import— добавить уже существующий облачный ресурс в state
Воркспейсы: осторожно с соблазном
terraform workspace позволяет держать несколько независимых state в одном backend. На первый взгляд удобно — один репозиторий для dev/staging/prod. На практике это часто приводит к путанице: легко применить план не в том окружении.
Более надёжный подход — отдельные директории или отдельные бакеты для каждого окружения с явными путями в key.
Версионирование и шифрование
Включите versioning на S3-бакете: это позволит откатиться к предыдущей версии state, если что-то пошло не так. Включите server-side encryption — state содержит чувствительные данные: IP-адреса, идентификаторы ресурсов, иногда секреты.
State никогда не должен попасть в git. Добавьте в .gitignore:
*.tfstate
*.tfstate.backup
.terraform/
Работа с большими state-файлами
Когда инфраструктура вырастает до тысяч ресурсов, plan и apply начинают тормозить: Terraform опрашивает API провайдера для каждого ресурса. Решение — разбить state на модули с отдельными бэкендами. Связь между модулями через terraform_remote_state или через внешние параметры (SSM, Vault).
Правильно организованный state — это фундамент надёжной инфраструктуры. Потратьте время на настройку remote backend с самого начала проекта, и вы избежите большинства проблем при масштабировании команды.
Наконец-то нормальное объяснение про блокировки — у нас в команде был случай, когда двое запустили apply одновременно и снесли prod окружение. Теперь DynamoDB обязателен.