linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
Intro
Lessons
Footer
linuxlab-УчебникиЦеныО платформеКонфиденциальность и куки
Copyright © 2026 LinuxLab. Все права защищены.
linuxlab.io
Учебники▾
  • Линукс и сети
    Файловая система, процессы, TCP/IP, BGP и OSPF
    →
  • Terraform и IaC
    HCL, state, plan/apply на sandbox LocalStack
    →
  • Git и GitHub
    Объектная модель, plumbing, ветвление, GitHub Actions
    →
Все учебники →
ЦеныО платформеВойтиСоздать аккаунт
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/kb/Advanced/tf-large-scale-state

kb/advanced ── Advanced ── advanced

Большой state, иерархия, blast-radius, naming

Один state на 5000 ресурсов = боль: refresh минуты, lock-contention, любой apply трогает всё. Решение, иерархия state'ов: network/iam отдельно, apps отдельно, между ними `terraform_remote_state`. Blast-radius, критерий разделения. Naming для бакетов и lock-таблиц предсказуемая структура.

view as markdownaka: terraform-state-at-scale, terraform-state-hierarchy, blast-radius

Признаки «state слишком большой»

  • terraform plan занимает > 60 секунд (refresh-фаза).
  • На apply одного маленького изменения lock держится 5+ минут.
  • 2+ команды дерутся за один lock.
  • PR ревьювится 3 дня, никто не понимает, что в plan'е, потому что он на 2000 строк.

Это сигналы для разбиения state'а.

Blast-radius, главный критерий

Что упадёт если этот state corrupt'нется или его потеряют?

Что в stateBlast-radius
Network (VPC, subnets)Все приложения этого VPC. Катастрофа.
IAM (roles, policies)Cross-account работа. Катастрофа.
One service appТолько этот сервис. Recoverable.
Dev-environmentТолько dev. Annoying.

Разделение по blast-radius:

state-account/      # account-level (org units, base IAM), мало меняется
state-network/      # VPC, subnets, transit gateway, редкие changes
state-platform/     # shared services (logging, monitoring)
state-apps/
  ├── web/
  ├── api/
  └── worker/

Каждый в своём S3-bucket-key, со своим lock.

Cross-state references

hcl
# state-apps/web/main.tf
data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "company-tf-state"
    key    = "state-network/terraform.tfstate"
    region = "us-east-1"
  }
}
resource "aws_instance" "web" {
  subnet_id = data.terraform_remote_state.network.outputs.public_subnet_ids[0]
  # ...
}

state-network должен иметь outputs:

hcl
output "public_subnet_ids" {
  value = aws_subnet.public[*].id
}

Web-state читает их. Только outputs видны cross-state, внутренние ресурсы и locals не доступны.

Это создаёт хрупкость: rename output'а в network = ломает все читающие state'ы. Версионируй outputs, не переименовывай легко.

Naming convention

Анти-паттерн: my-state-bucket/terraform.tfstate для всего.

Хорошо:

s3://company-tf-state/
├── prod/network/terraform.tfstate
├── prod/iam/terraform.tfstate
├── prod/apps/web/terraform.tfstate
├── prod/apps/api/terraform.tfstate
├── stage/network/terraform.tfstate
├── stage/iam/terraform.tfstate
└── ...

Иерархия: <env>/<component>/terraform.tfstate. Префикс env'а первый, IAM-policy легко разрешает «доступ только в prod/*».

DynamoDB lock-table:

  • Одна таблица на account, разные partition-keys для разных state'ов.
  • Или таблица per env (для жёсткой изоляции). Просто, на 100 state'ов становится много таблиц.

Стандарт, одна таблица, partition-key = LockID, Terraform сам генерит. Конфликта нет.

Hierarchy в IAM

Cross-state references требуют IAM-доступа. Web-app's role должна читать network-state:

hcl
resource "aws_iam_role_policy" "web_read_network_state" {
  role = aws_iam_role.web_tf_runner.name
  policy = jsonencode({
    Statement = [{
      Effect   = "Allow"
      Action   = ["s3:GetObject"]
      Resource = ["arn:aws:s3:::company-tf-state/prod/network/terraform.tfstate"]
    }]
  })
}

Web НЕ должен иметь права на network-state-write. Это разделение иначе compromised web-CI может сломать VPC.

Split-стратегии

Когда монолит state большой, разделить. Способы:

1. По функции (layer)

iam/, network/, data/, apps/

Network редко меняется, apps часто. Lock-contention падает.

2. По environment

dev/, stage/, prod/

Не зависят друг от друга. Подходит когда env'ы изолированы.

3. По tenant

tenants/customer-A/, tenants/customer-B/, ...

SaaS-инфра с per-customer ресурсами. Каждый tenant, свой state.

Обычно комбинация: prod/network/, prod/tenant-X/, stage/network/, и т.д. Три измерения: env × layer × tenant.

Split-миграция

Допустим, всё в monolith/terraform.tfstate. Хочешь вынести network:

  1. Создай новый state network/terraform.tfstate (пустой).

  2. terraform state mv с одного state в другой через state pull / state push (нативного cross-state mv нет, нужен манёвр):

    bash
    # из monolith
    terraform state mv -state-out=/tmp/network.tfstate aws_vpc.main aws_vpc.main
    # ... все network-ресурсы
    # в network-state
    terraform state push /tmp/network.tfstate
  3. removed блоки в monolith HCL: ресурсы переехали, не нужно destroy.

  4. terraform_remote_state в monolith: читает outputs из новой network.

  5. Apply обоих: plan'ы должны быть no changes.

Подробнее в tf-state-manipulation и tf-blue-green-migration.

Когда split, не нужен

  • Меньше 200 ресурсов в state.
  • Один env, одна команда, нет lock-contention.
  • Plan < 30s, apply разумный.

Преждевременный split добавляет orchestration-cost (terragrunt или ручной shell-script для apply'я в правильном порядке) и cross-state versioning.

Подводные камни

  • Cross-state coupling, хрупкое. Output удалили в network → web-state ломается на следующем apply. Версионируй outputs (output "vpc_id_v2").

  • terraform_remote_state гонит data на каждом refresh. Большой state

    • много reader'ов = много S3 GET'ов. Performance issue на 50+ reader'ах.
  • Lock-table должен быть рядом. DynamoDB-lock в us-east-1, state в eu-west-1, каждый lock-acquire через cross-region call. Замедление.

  • Backup восстановить сложнее. На один монолит, один state-restore. На 30 state'ов, 30 restore'ов, в правильном порядке.

  • Permissions для cross-state. IAM-роль каждого reader'а должна иметь s3:GetObject на конкретные state-keys. Без удачного naming-конвенции, police IAM-policy plate of spaghetti.

  • Импорт обратно в монолит, дорого. Раз разделил, обратно объединять через state mv/push, операция на часы. Делать разделение осознанно.

  • Apply-orchestration. Если network должен applе'ться до apps, кто-то этим orchestrates. Terragrunt, да; вручную, порядок запоминать.

§ команды

bash
terraform state pull > local-state.json

Скачать state локально, для inspect или backup.

bash
terraform state list | wc -l

Сколько ресурсов в state. > 500, задумайся о split'е.

bash
aws s3api list-objects --bucket company-tf-state --prefix prod/

Все state-keys в prefix prod. Сводка структуры.

bash
terraform state mv -state-out=/tmp/X.tfstate aws_vpc.main aws_vpc.main

Вынести ресурс в другой state-файл.

§ см. также

  • tf-remote-backend-s3Remote state в S3: бакет, DynamoDB lock, encryptionS3-backend хранит `terraform.tfstate` в бакете, DynamoDB-таблица даёт блокировку одного-apply-за-раз. Конфигурация, в блоке `backend "s3"` внутри `terraform { ... }`. State в S3. Это единственный source of truth, локального файла больше нет. Переезд с local на S3, через `terraform init -migrate-state`.
  • tf-stateState: память Terraform о созданномState. JSON-файл terraform.tfstate, где Terraform записывает, что он создал в облаке. Без него Terraform не знал бы, какой бакет «его», а какой чужой. Содержит ID ресурсов, все атрибуты, и часто секреты. Самая чувствительная часть проекта.
  • tf-terragruntTerragrunt, DRY-обёртка над TerraformTerragrunt, обёртка Gruntwork, решает проблему «directory-per-env» дублирования. Объявляешь `terragrunt.hcl` с `inputs` и `include`'ами; Terragrunt генерирует backend.tf, provider.tf и main.tf на лету и вызывает `terraform`. Альтернатива, workspaces (опасно), copy-paste (плохо), CDKTF (другой стек). Стоимость, ещё один tool в цепочке, ещё один HCL-диалект.
  • tf-dag-internalsDAG в Terraform, как строится граф зависимостейTerraform строит DAG (directed acyclic graph) из ресурсов и их зависимостей. На plan/apply граф «обходится» в топологическом порядке, параллельно где можно (limit, `-parallelism`, дефолт 10). Implicit dependencies, через interpolation; explicit, `depends_on`. Цикл = `Cycle: ...` ошибка. Понимание DAG объясняет почему apply иногда «застревает» и как ускорить большой граф.
Footer
linuxlab-
Copyright © 2026 LinuxLab. Все права защищены.
Учебники
Цены
О платформе
Конфиденциальность и куки