Когда вы впервые описываете инфраструктуру кодом и запускаете apply на своей машине — всё работает, и это вдохновляет. Но между «работает у меня в одиночку» и «работает в команде на продакшене» лежит несколько важных вещей, о которых учебники часто молчат. State, секреты, разделение окружений и автоматическая доставка — вот что превращает учебный пример в настоящий проект.
Эта статья — обзорная карта этих тем для тех, кто уже попробовал инфраструктуру как кода (Infrastructure as Code, IaC — описание серверов, сетей и сервисов в виде файлов конфигурации) и хочет понять, чего не хватает до «по-взрослому». Если базовые понятия пока в тумане, начните с раздела Основы IaC, а потом возвращайтесь.
Где хранить state и зачем его блокировать
State (состояние) — это файл, в котором Terraform запоминает, что он уже создал в облаке: какие ресурсы, с какими ID и настройками. Без него Terraform не знает, что менять, а что оставить. Думайте о нём как о бухгалтерской книге: в реальности — серверы в AWS, в книге — записи о них, и они должны сходиться.
Когда вы учитесь, state лежит файлом terraform.tfstate рядом с кодом. Для одного человека это нормально. Но как только появляется второй разработчик — начинается беда: у каждого своя копия книги, и они расходятся.
Решение — remote state (удалённое состояние): хранить файл не локально, а в общем месте, куда смотрят все. На AWS это обычно бакет Amazon S3. Тогда книга одна на всех.
terraform {
backend "s3" {
bucket = "myteam-tfstate"
key = "prod/network/terraform.tfstate"
region = "eu-central-1"
}
}
Но общий файл рождает вторую проблему: что если два человека запустят apply одновременно? Они затрут правки друг друга и могут испортить state. Чтобы этого не случилось, нужна блокировка (locking) — пока один apply идёт, остальные ждут, как очередь в одну кабинку.
Классический способ — таблица в DynamoDB: Terraform создаёт там запись-замок на время операции.
terraform {
backend "s3" {
bucket = "myteam-tfstate"
key = "prod/network/terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "tfstate-lock"
}
}
Начиная с Terraform 1.10 появился более простой вариант — нативная блокировка средствами самого S3, отдельная таблица не нужна; вариант через DynamoDB при этом считается устаревшим:
terraform {
backend "s3" {
bucket = "myteam-tfstate"
key = "prod/network/terraform.tfstate"
region = "eu-central-1"
use_lockfile = true
}
}
Полезная привычка: включить версионирование бакета S3 — тогда испорченный state можно откатить к предыдущей версии.
Важная развилка инструментов. У Terraform state — ваша забота. А вот CloudFormation и CDK (надстройка над CloudFormation, где инфраструктура описывается на обычном языке программирования) состояние ведут сами внутри AWS: отдельного файла нет, бакет под state не нужен, блокировка тоже на стороне AWS. Подробнее об инструментах — в статьях про Terraform, CloudFormation и CDK.
Секреты: чего нельзя делать
Секрет — это любое значение, утечка которого опасна: пароль к базе, ключ API, токен. С секретами в IaC два железных правила.
Первое: не коммитить секреты в git. Файл с паролем в репозитории — это пароль, который видят все с доступом к коду, и который останется в истории навсегда, даже если вы потом его удалите.
Второе, менее очевидное: секрет не должен лежать открытым в state. Если вы впишете пароль прямо в конфигурацию, Terraform сохранит его в state-файле в открытом виде — а значит, любой, кто прочтёт state, узнает пароль. Это та же утечка, просто в другом месте.
Правильный подход — хранить секреты в специальном сервисе и подтягивать их оттуда:
- AWS Secrets Manager — хранилище с шифрованием и автоматической ротацией (сменой) паролей, удобно для учётных данных к базам.
- SSM Parameter Store — параметры приложения; тип
SecureStringшифрует значение ключом KMS.
В Terraform секрет читают через data source — ссылку на уже существующее значение, а не на то, что создаёт сам Terraform:
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/db/password"
}
Хорошая дисциплина — не плодить чувствительные значения в state без нужды и в любом случае закрывать сам state-файл строгими правами доступа. Управление доступом — тема статьи про IAM.
Несколько окружений (dev, prod)
Почти у любого проекта есть как минимум два окружения: dev — где экспериментируют и не страшно сломать, и prod — где живут реальные пользователи и ломать нельзя. Главная цель — чтобы случайная правка в dev физически не могла задеть prod.
В Terraform есть два пути. Workspaces (рабочие пространства) разделяют state внутри одного бакета и одной конфигурации — это удобно для мелочей, но опасно для prod: легко перепутать активное пространство и применить изменения не туда. Для надёжной изоляции продакшена лучше отдельные директории и отдельный state на каждое окружение: у dev своя папка и свой ключ state, у prod — свои.
environments/
dev/ -> key = "dev/terraform.tfstate"
prod/ -> key = "prod/terraform.tfstate"
Разные файлы state — разные «бухгалтерские книги», и одно окружение не видит ресурсы другого. В мире CloudFormation/CDK тот же принцип достигается отдельными стеками (stack — именованный набор ресурсов): myapp-dev и myapp-prod существуют независимо.
IaC в конвейере доставки
Запускать apply руками со своего ноутбука — нормально, пока вы один и проект учебный. В команде это превращается в конвейер доставки (CI/CD — автоматический процесс сборки и выкатки изменений), и инфраструктура едет по тем же рельсам, что и код.
Базовый рабочий процесс простой и пошаговый:
- Вы открываете pull request (запрос на слияние ветки) с правкой инфраструктуры.
- Конвейер автоматически запускает
terraform plan— это сухой прогон, который показывает, что изменится, ничего не трогая. План попадает в обсуждение pull request, и коллеги его смотрят. - После одобрения и слияния (merge) конвейер запускает
terraform apply— изменения применяются. В CloudFormation/CDK ту же роль играютcloudformation deployиcdk deploy.
Так ни одно изменение продакшена не происходит «втихую»: сначала видимый план на ревью, потом применение.
Остаётся вопрос: как конвейеру войти в AWS? Соблазн — положить вечный ключ доступа (access key) в настройки CI. Это плохая идея: такой ключ долгоживущий, и если он утечёт, им можно пользоваться сколько угодно. Правильный способ — OIDC-федерация (OpenID Connect): CI на лету получает короткоживущий токен, действующий ровно на одну задачу, и AWS выдаёт временные права по доверию, а не по сохранённому паролю.
permissions:
id-token: write
contents: read
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::111122223333:role/ci-terraform
aws-region: eu-central-1
Принципы самого конвейера — в разделах Принципы pipeline и Стратегии релизов.
Как ловить drift
Drift (дрейф) — это расхождение между тем, что описано в коде, и тем, что реально в облаке. Появляется он, когда кто-то правит ресурс вручную через консоль: код говорит одно, реальность — другое, и при следующем apply бывают сюрпризы.
Ловят дрейф проще всего регулярной проверкой. В Terraform это периодический terraform plan: если план не пустой, хотя вы ничего не меняли — значит, реальность ушла от кода.
terraform plan -detailed-exitcode
У CloudFormation для этого есть встроенное обнаружение дрейфа (drift detection):
aws cloudformation detect-stack-drift --stack-name myapp-prod
А CDK предоставляет команду, которая под капотом вызывает ту же проверку CloudFormation:
cdk drift
Хорошая привычка — гонять такую проверку по расписанию (например, ночью) и оповещать команду, если дрейф найден. Тогда ручные правки не накапливаются незаметно.
Где это применяется
Эти темы всплывают ровно в тот момент, когда инфраструктура из личного эксперимента становится командной. Remote state и блокировка — как только над проектом работает больше одного человека. Разделение окружений — как только появляется реальный продакшен, который нельзя ронять. Конвейер с планом на ревью — когда изменения инфраструктуры должны быть прозрачными и обратимыми, как обычный код.
Типичные ошибки новичков: оставить state локальным файлом и потом долго мирить расхождения; вписать пароль прямо в конфигурацию и забыть, что он осел в state; путать workspace и применить prod-правку в dev; положить вечный ключ AWS в настройки CI. Каждой из них соответствует прямое лекарство из этой статьи.
Что учить дальше: устройство конкретных инструментов — Terraform, CloudFormation, CDK; базу облака, чтобы понимать, что именно вы описываете кодом — Основы AWS, сети, IAM; и принципы доставки в целом — ветки и релизы. Если инфраструктура едет в Kubernetes, пригодятся основы Kubernetes и деплой и конфигурация.