Terraform и Ansible: state, идемпотентность и границы ответственности
Блок про инфраструктуру как код, где почти всегда спрашивают про state — и почти всегда на нём же спотыкаются.
Вопрос: «Зачем Terraform хранит state? Что произойдёт, если два инженера применят конфигурацию одновременно, и как этого избежать?»
Что на самом деле проверяет интервьюер
State — это сердце Terraform и источник большинства реальных инцидентов с IaC. Вопрос проверяет, работал ли кандидат с Terraform в команде, а не в одиночку на ноутбуке. Второй слой — понимание идемпотентности: почему повторный запуск должен ничего не менять и почему это свойство важнее удобного синтаксиса.
Развёрнутый ответ: зачем нужен state
Terraform сопоставляет три вещи: ваш код (желаемое состояние), state-файл (что Terraform создавал в прошлый раз) и реальность в облаке (её он получает через API при refresh). План — это разница между ними.
Без state Terraform не знал бы, что aws_instance.web из кода — это конкретная машина i-0abc123. Он бы либо создавал дубликаты, либо не мог удалять: удаление ресурса из кода означает «удали то, что раньше было создано по этому адресу», а узнать это можно только из state. Дополнительно state хранит зависимости между ресурсами (нужно для корректного порядка удаления) и кэширует атрибуты, чтобы не опрашивать API по каждому полю.
terraform plan # показать разницу: код ↔ state ↔ реальность
terraform apply # привести реальность к коду и обновить state
terraform state list # что Terraform считает своим
terraform import aws_instance.web i-0abc # взять под управление существующий ресурс
terraform state rm aws_instance.web # забыть ресурс, НЕ удаляя его в облаке
Проблема одновременного применения
Если state лежит локально, у каждого инженера своя версия правды — расхождение неизбежно. Если state общий, но применяют одновременно, две операции затирают записи друг друга: получаются «осиротевшие» ресурсы, за которые никто не платит вниманием, но за которые платит компания.
Решение — remote backend с блокировкой. State хранится централизованно (S3, GCS, Terraform Cloud), а на время apply берётся эксклюзивная блокировка: второй инженер получит сообщение об ожидании вместо гонки.
terraform {
backend "s3" {
bucket = "acme-tfstate"
key = "prod/network/terraform.tfstate"
region = "eu-central-1"
encrypt = true
use_lockfile = true
}
}
Что ещё стоит сказать про state, чтобы ответ выглядел зрелым:
- State содержит секреты в открытом виде — пароли БД, приватные ключи, токены попадают туда как атрибуты ресурсов. Поэтому обязательны шифрование бакета, строгий доступ и запрет коммитить state в git.
- Включите версионирование бакета. Испорченный state восстанавливается откатом на предыдущую версию — это самая частая аварийная процедура.
- Разделяйте state по окружениям и доменам (сеть, кластер, приложения). Один гигантский state означает долгий plan и общий радиус поражения при ошибке.
Вопрос 2: что такое идемпотентность
Идемпотентность — свойство операции давать один и тот же результат независимо от того, применили её один раз или десять. Второй terraform apply без изменений в коде должен сказать «No changes» и ничего не тронуть.
Зачем это нужно: инструмент становится безопасным для повторного запуска. Пайплайн можно перезапустить после сетевого сбоя, не думая, не создастся ли вторая база данных. Именно поэтому в Ansible пишут не «выполни команду», а «приведи к состоянию»:
- name: Установить и настроить nginx
hosts: web
become: true
tasks:
- name: Пакет установлен
ansible.builtin.package:
name: nginx
state: present # идемпотентно: повторный запуск ничего не делает
- name: Конфиг на месте
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: "0644"
notify: reload nginx # handler сработает ТОЛЬКО при изменении файла
- name: Сервис запущен и в автозагрузке
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: reload nginx
ansible.builtin.service:
name: nginx
state: reloaded
Главный враг идемпотентности — модуль shell или command: Ansible не знает, что делает ваша команда, и выполнит её при каждом запуске. Отсюда правило: использовать специализированные модули, а если без shell никак — добавлять creates:, removes: или changed_when:.
Вопрос 3: Terraform или Ansible
Ловушка для тех, кто считает их конкурентами. Они решают разные задачи и на практике работают в связке.
| Критерий | Terraform | Ansible |
| Подход | декларативный | процедурный (с идемпотентными шагами) |
| Задача | provisioning: создать сети, кластеры, базы, балансировщики | configuration management: настроить систему внутри машины |
| Состояние | хранит state | state не хранит, сверяется с фактом на хосте |
| Агент | обращается к API провайдера | по SSH, агент не нужен |
| Удаление | умеет (destroy) | только если вы явно описали |
Типичная связка: Terraform поднимает VPC, узлы и managed-базы, Ansible доводит конфигурацию на машинах. В мире Kubernetes роль Ansible часто берут на себя Helm и GitOps-инструменты (Argo CD, Flux), а Terraform остаётся для облачных ресурсов вокруг кластера. Отдельно стоит упомянуть подход immutable infrastructure: вместо донастройки живых серверов пересобирается образ (Packer) и заменяется целиком — тогда configuration management нужен только на этапе сборки образа.
Типичные ошибки кандидатов
- Держат state локально или коммитят его в git — с секретами внутри.
- Не знают про блокировку и не могут объяснить, что случится при параллельном apply.
- Правят ресурсы руками в консоли облака, а потом удивляются дрейфу конфигурации и агрессивному плану.
- Путают
terraform state rm(забыть ресурс) иterraform destroy(удалить его на самом деле). - Пишут плейбуки на сплошных
shell-командах, теряя идемпотентность. - Противопоставляют Terraform и Ansible, вместо того чтобы объяснить разделение зон ответственности.
Как ответить кратко (20–30 секунд)
«State — это карта соответствия между ресурсами в коде и реальными объектами у провайдера, плюс их зависимости. Без него Terraform не смог бы понять, что удалять и что обновлять, и плодил бы дубликаты. Если два инженера применяют одновременно, записи затирают друг друга и появляются потерянные ресурсы — поэтому state держим в remote backend с блокировкой, с шифрованием и версионированием, никогда не в git: там лежат секреты открытым текстом. Идемпотентность означает, что повторный apply без изменений ничего не делает; в Ansible это достигается модулями «приведи к состоянию» вместо голых shell-команд. Terraform создаёт инфраструктуру, Ansible настраивает систему внутри — они дополняют друг друга.»