Адаптивный перевод статьи Terraform State Locking with S3 (devopscube). Изложение своими словами; конфиги и команды — как в оригинале. Все права на исходный материал принадлежат авторам devopscube. Диаграмма ниже — оригинальная (Mermaid), а не перенос картинок из статьи.

Что такое блокировка стейта и зачем она

Terraform хранит состояние инфраструктуры (state) в одном файле. Если два человека (или два CI-джоба) одновременно запустят terraform apply на одном и том же стейте — они начнут писать в него параллельно, и это гонка: state может побиться, ресурсы — рассинхронизироваться с реальностью.

Блокировка стейта (state locking) решает это: перед изменением стейта Terraform берёт эксклюзивную блокировку, а остальные процессы ждут или получают понятную ошибку «залочено».

Классический подход: DynamoDB

Исторически для S3-backend блокировку делали через отдельную таблицу DynamoDB:

Подход проверенный временем и даёт более строгие гарантии консистентности, но требует поднимать и обслуживать лишний ресурс (таблицу DynamoDB) — и платить за неё.

Новый подход: нативный lockfile в S3

В Terraform 1.10 появилась (как экспериментальная) возможность блокировать стейт прямо в S3, без DynamoDB — через опцию use_lockfile.

Работает это на фиче S3 conditional writes (условная запись, доступна в AWS с августа 2024): S3 умеет атомарно создать объект «только если его ещё нет» (If-None-Match). Terraform использует это, чтобы создать рядом со стейтом файл-блокировку .tflock:

⚠️ Официально это «eventually consistent» механизм — теоретически при очень высокой конкуренции возможны гонки. Для команд с интенсивными параллельными запусками это стоит учитывать (см. раздел «Что выбрать»).

Как это выглядит по шагам

  sequenceDiagram
    autonumber
    participant U as terraform apply
    participant S3 as S3 (bucket)
    U->>S3: PUT state.tfstate.tflock (If-None-Match: *)
    alt файла ещё нет
        S3-->>U: 200 — блокировка взята
        U->>S3: читает/пишет state.tfstate
        U->>S3: DELETE state.tfstate.tflock
        S3-->>U: блокировка снята
    else .tflock уже существует
        S3-->>U: 412 Precondition Failed
        U-->>U: Error: state locked — ждём/выходим
    end

Конфигурация backend

Всё, что нужно — добавить use_lockfile = true в блок S3-backend (подставьте свои bucket, key и region):

HCL
terraform {
  backend "s3" {
    bucket       = "my-terraform-state-bucket"
    key          = "terraform/state.tfstate"
    region       = "us-west-1"
    use_lockfile = true
  }
}
Нажмите, чтобы развернуть и увидеть больше

Никаких dynamodb_table больше не нужно. После правки:

BASH
terraform init
terraform apply
Нажмите, чтобы развернуть и увидеть больше

Во время apply в бакете рядом со state.tfstate появится state.tfstate.tflock, а по завершении — исчезнет. Если в этот момент второй запустит apply, он получит ошибку блокировки.

Требования

IAM-права

Процессу Terraform нужны права на объект стейта и на lock-файл рядом с ним. Минимально:

JSON
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "TerraformStateAndLock",
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::my-terraform-state-bucket/terraform/state.tfstate",
        "arn:aws:s3:::my-terraform-state-bucket/terraform/state.tfstate.tflock"
      ]
    },
    {
      "Sid": "ListStateBucket",
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": "arn:aws:s3:::my-terraform-state-bucket"
    }
  ]
}
Нажмите, чтобы развернуть и увидеть больше

Best practices

  1. Включите versioning на бакете стейта — чтобы можно было откатиться к прежней версии state.
  2. Ограничьте доступ IAM-политиками — стейт содержит чувствительные данные.
  3. Включите шифрование S3 (SSE-S3 или SSE-KMS) для файла стейта.
  4. Аккуратно снимайте блокировку вручную, если процесс умер аварийно и .tflock завис (terraform force-unlock <LOCK_ID> или удаление объекта — осознанно).
  5. Разносите стейты по проектам/окружениям (отдельный key), а не держите всё в одном файле.

Что выбрать: use_lockfile или DynamoDB

Нативный S3 use_lockfile — когда:

DynamoDB — когда:

Итог

Нативная блокировка стейта в S3 через use_lockfile убирает необходимость в отдельной таблице DynamoDB — меньше ресурсов, проще setup, дешевле. Для небольших/средних сетапов с умеренной конкуренцией это отличный дефолт. Там, где несколько команд активно бьются за один стейт и нужны железные гарантии — DynamoDB пока остаётся более надёжным выбором.

Авторские права

Автор: Vasiliy Fakunin

Ссылка: https://notes.melancholic.tech/posts/terraform-state-locking-s3/

Лицензия: CC BY-NC-SA 4.0

Использование материалов блога разрешается при условии: указания авторства/источника, некоммерческого использования и сохранения лицензии.

Начать поиск

Введите ключевые слова для поиска статей

↑↓
ESC
⌘K Горячая клавиша