Terraform
Описывайте серверы, DNS и облачные ресурсы в коде, проверяйте план, затем применяйте.
За 30 секунд
Terraform позволяет описать инфраструктуру (серверы, базы данных, DNS-записи, бакеты, права доступа) в виде файлов с кодом. Он сравнивает этот код с тем, что реально существует, и показывает план: что именно он создаст, изменит или удалит. После вашего одобрения он вносит изменения через API каждого провайдера. Инфраструктура становится проверяемой на ревью, воспроизводимой и задокументированной в Git.
Не в моём ежедневном стеке — я понимаю принципы и изучу детали, когда это понадобится проекту.
Почему это важно
- Infrastructure as code важна, потому что клики в веб-консоли невозможно повторить, нельзя отревьюить, и через месяц о них уже никто не помнит.
- Она нужна команде, когда та управляет больше чем горсткой ресурсов, несколькими окружениями или когда инфраструктуру меняют несколько человек.
- Шаг plan — это страховочная сетка: вы видите, что изменение уничтожит базу данных, до того как это произошло, а не после.
- Моих текущих серверов достаточно мало, чтобы управлять ими вручную по задокументированным runbook'ам; Terraform — естественный следующий шаг, когда окружений становится больше или их нужно быстро и идентично пересоздавать.
Как это работает
01Идея: инфраструктура как код
Infrastructure as code означает, что ваши серверы, сети и DNS описаны в текстовых файлах, хранятся в Git и меняются через pull request'ы, как код приложения. Terraform использует декларативный язык HCL: вы описываете желаемое конечное состояние (один сервер такого-то размера, одна DNS-запись, указывающая на него), а не шаги, как к нему прийти. Шаги Terraform вычисляет сам. Польза вполне конкретная. Staging-окружение может быть точной копией продакшена. Новый человек в команде читает код и понимает инфраструктуру. Изменения проходят ревью до того, как случатся, а история Git показывает, кто что изменил и зачем. Восстановление после аварии ускоряется, потому что инфраструктуру можно пересоздать из кода, хотя данные всё равно придётся брать из бэкапов.
- Декларативно: описываете что, а не как.
- Версионируется и проходит ревью, как код приложения.
- Terraform создаёт инфраструктуру; инструменты вроде Ansible настраивают то, что работает внутри серверов.
02Провайдеры и ресурсы
Сам Terraform ничего не знает об AWS или DigitalOcean. Провайдеры — это плагины, которые переводят ваш код в вызовы API одной платформы; есть провайдеры для AWS, Google Cloud, Azure, DigitalOcean, Hetzner, Cloudflare, GitHub, Kubernetes и сотен других сервисов. Вы объявляете нужные провайдеры и фиксируете их версии, затем terraform init скачивает их и записывает точные версии в lock-файл, который вы коммитите. Блок resource описывает один управляемый объект: сервер, бакет, DNS-запись. Блок data читает что-то уже существующее, не управляя им. Переменные делают код переиспользуемым, outputs выводят полезные значения вроде IP-адреса, а учётные данные берутся из переменных окружения, а не из кода.
terraform {
required_version = ">= 1.10"
required_providers {
digitalocean = { source = "digitalocean/digitalocean", version = "~> 2.0" }
cloudflare = { source = "cloudflare/cloudflare", version = "~> 5.0" }
}
}
# tokens come from DIGITALOCEAN_TOKEN and CLOUDFLARE_API_TOKEN env vars
provider "digitalocean" {}
provider "cloudflare" {}
variable "ssh_key_fingerprint" { type = string }
variable "cloudflare_zone_id" { type = string }
03Пример: сервер и его DNS-запись
Вот законченный маленький кусочек реальной инфраструктуры: сервер на Ubuntu и DNS-запись, указывающая на него хостнейм. Обратите внимание на ссылку digitalocean_droplet.web.ipv4_address внутри DNS-записи. Terraform читает такие ссылки, чтобы построить граф зависимостей: так он знает, что сервер должен существовать до создания записи, и может создавать независимые ресурсы параллельно. Если позже вы поменяете размер сервера, план покажет обновление на месте; если поменяете образ — покажет, что сервер нужно уничтожить и создать заново, и это ровно тот сюрприз, ради выявления которого план и существует. После apply output выведет новый IP.
resource "digitalocean_droplet" "web" {
name = "web-1"
image = "ubuntu-24-04-x64"
region = "fra1"
size = "s-1vcpu-2gb"
ssh_keys = [var.ssh_key_fingerprint]
}
resource "cloudflare_dns_record" "app" {
zone_id = var.cloudflare_zone_id
name = "app.example.com"
type = "A"
content = digitalocean_droplet.web.ipv4_address
ttl = 1
proxied = true
}
output "server_ip" { value = digitalocean_droplet.web.ipv4_address }
04Plan и apply
У повседневной работы чёткий ритм. terraform init готовит рабочую папку и скачивает провайдеры. terraform fmt и validate ловят проблемы со стилем и синтаксисом. terraform plan сравнивает три вещи: ваш код, state-файл и реальные ресурсы, — а затем печатает каждое действие со значком: плюс — создание, тильда — обновление на месте, минус — удаление, минус-плюс — замена. Внимательно читайте план, особенно любые удаления. Если сохранить план в файл и применить именно его, то выполнится ровно то, что вы проверили. В команде CI запускает plan на каждый pull request и публикует результат для ревью; apply запускается после мерджа из CI, а не с чьего-то ноутбука. Используйте prevent_destroy для ценных ресурсов вроде баз данных.
terraform init
terraform fmt -check
terraform validate
terraform plan -out=tfplan
terraform apply tfplan
# inspect and troubleshoot
terraform state list
terraform output server_ip
05State, удалённый state и блокировки
Terraform хранит state-файл: соответствие между каждым ресурсом в коде и реальным объектом, которым он управляет, с его ID и атрибутами. Без state Terraform не может знать, что web в вашем коде — это сервер 12345 у провайдера. По умолчанию state — локальный файл, и это ломается, как только появляются два человека или CI-задача. Храните его удалённо — в бакете S3 или совместимом хранилище, в Terraform Cloud или другом backend'е — с включённым версионированием, чтобы можно было восстановиться после неудачной записи. Блокировка не даёт двум apply запуститься одновременно и испортить state. Backend S3 теперь поддерживает нативную блокировку через use_lockfile; старый способ с таблицей DynamoDB признан устаревшим. State может содержать секреты вроде паролей к базе, поэтому шифруйте его и ограничивайте доступ.
terraform {
backend "s3" {
bucket = "example-terraform-state"
key = "prod/terraform.tfstate"
region = "eu-central-1"
encrypt = true
use_lockfile = true
}
}
06Модули, дрифт и ландшафт инструментов
Модуль — это папка с кодом Terraform со входами и выходами, как функция. Напишите модуль веб-сервера один раз и вызывайте его для staging и продакшена с разными размерами. Держите модули маленькими и сфокусированными, фиксируйте версии общих модулей и храните окружения в отдельных state-файлах, чтобы ошибка в staging не могла задеть продакшен. Дрифт — это когда реальность перестала совпадать с кодом, обычно потому что кто-то поменял что-то руками в консоли. terraform plan его выявляет; дальше вы либо обновляете код, чтобы он совпадал, либо делаете apply, чтобы вернуть объявленное состояние. Что касается инструментов: в 2023 году HashiCorp перевела Terraform на Business Source License, а теперь сама входит в IBM. OpenTofu — open-source форк, в основном совместимый, с дополнениями вроде встроенного шифрования state. Pulumi использует TypeScript, Python или Go вместо HCL.
module "web_staging" {
source = "./modules/web-server"
name = "web-staging"
size = "s-1vcpu-1gb"
}
module "web_prod" {
source = "./modules/web-server"
name = "web-prod"
size = "s-2vcpu-4gb"
}
Когда применять
- Несколько окружений (staging, продакшен), которые должны оставаться одинаковыми по структуре.
- Команды, где инфраструктуру меняет больше одного человека и изменениям нужно ревью.
- Облачные конфигурации с множеством связанных ресурсов: сети, IAM, базы данных, DNS, CDN.
- Когда нужно быстро пересоздать инфраструктуру после аварии или в новом регионе.
Когда не стоит
- Один-два долгоживущих сервера, которые редко меняются, — задокументированного runbook'а может хватить.
- Настройка софта внутри серверов (пакеты, файлы, сервисы) — это работа Ansible, cloud-init или Docker-образов.
- Частые деплои приложения: для кода используйте CI/CD, а Terraform — для платформы под ним.
Альтернативы
- OpenTofu
Open-source форк Terraform, для большинства проектов — прямая замена, добавляет шифрование state.
- Pulumi
Infrastructure as code на TypeScript, Python, Go или C# с настоящими циклами и тестами.
- AWS CloudFormation / CDK
Родной IaC для AWS; глубокая интеграция с AWS, но только AWS.
- Ansible
Управление конфигурацией через SSH; дополняет Terraform, а не заменяет его.
Лучшие практики
- С первого дня используйте удалённый state с версионированием, шифрованием и блокировкой.
- Фиксируйте версии Terraform и провайдеров и коммитьте lock-файл зависимостей.
- Запускайте plan в CI на каждый pull request, а apply — только из CI после ревью.
- Разделяйте state по окружениям и крупным компонентам, чтобы ограничить радиус поражения.
- Никогда не хардкодьте секреты; передавайте их через переменные окружения или менеджер секретов.
- Защищайте критичные ресурсы через prevent_destroy и проверяйте каждое удаление в плане.
- Запускайте plan по расписанию, чтобы рано обнаруживать дрифт.
Частые ошибки
- Коммитить terraform.tfstate в Git, раскрывая секреты и вызывая конфликты.
- Делать apply, не прочитав план, и заменить базу данных вместо её обновления.
- Менять ресурсы руками в консоли, а потом удивляться, что apply откатывает изменения.
- Один гигантский state на всё, так что любое мелкое изменение требует медленного и рискованного plan.
- Потерять state-файл и импортировать каждый ресурс вручную.
Глубже
07Как на самом деле работает plan: граф, неизвестные значения и порядок замены
Terraform превращает вашу конфигурацию в граф зависимостей. Каждый resource, data source, variable и output — это вершина, а каждая ссылка создаёт ребро. Во время plan он обновляет каждый управляемый ресурс у провайдера, сравнивает обновлённый state с конфигурацией и спрашивает провайдера, какое действие нужно. Значения, которые появляются только после создания, например IP нового сервера, отображаются как known after apply и передаются дальше как неизвестные, поэтому некоторые планы показывают целый каскад изменений. Terraform обходит граф параллельно, по умолчанию по десять операций одновременно, это настраивается через -parallelism. Когда аргумент нельзя обновить на месте, провайдер помечает его как forcing replacement, и по умолчанию Terraform сначала уничтожает старый объект, а потом создаёт новый. create_before_destroy меняет порядок на обратный, чтобы избежать даунтайма, — при условии, что имена не конфликтуют. Используйте depends_on только для скрытых зависимостей, которые не выражены ни одной ссылкой.
resource "aws_launch_template" "web" {
name_prefix = "web-" # unique names allow create-before-destroy
image_id = var.ami_id
instance_type = "t4g.small"
lifecycle {
create_before_destroy = true
ignore_changes = [tags["LastScannedAt"]] # set by another tool
}
}
08count против for_each и рефакторинг без уничтожения
count создаёт список экземпляров с адресацией по индексу: server[0], server[1], server[2]. Удалите средний элемент из входного списка — и все последующие индексы сдвинутся, поэтому Terraform запланирует уничтожить и пересоздать серверы, которые на самом деле не менялись. for_each создаёт map с адресацией по ключу, server["api"], server["worker"], так что удаление одного ключа затрагивает только этот экземпляр; предпочитайте его, когда у элементов есть естественная идентичность. Переименование ресурса или перенос в модуль тоже меняет его адрес, и без подсказки Terraform уничтожил бы старый адрес и создал новый. Блок moved объявляет переименование прямо в коде, поэтому план показывает перемещение без изменений, а коллеги и CI подхватывают его автоматически — terraform state mv так не умеет. Чтобы перестать управлять ресурсом, не уничтожая его, используйте блок removed с lifecycle destroy = false. Чтобы взять под управление существующий ресурс, используйте блок import.
resource "digitalocean_droplet" "app" {
for_each = { api = "s-2vcpu-4gb", worker = "s-1vcpu-2gb" }
name = "app-${each.key}"
size = each.value
image = "ubuntu-24-04-x64"
region = "fra1"
}
moved {
from = digitalocean_droplet.web
to = digitalocean_droplet.app["api"]
}
import {
to = cloudflare_dns_record.legacy
id = "zone_id/record_id"
}
09Секреты: sensitive, ephemeral и write-only значения
Пометка переменной или output как sensitive = true лишь скрывает значение в выводе plan и в логах; в state-файл оно всё равно записывается открытым текстом. Именно поэтому state должен быть зашифрован, а доступ к нему — ограничен. Новые версии идут дальше. В Terraform 1.10 появились ephemeral input-переменные, outputs и ephemeral-ресурсы — значения, которые существуют во время запуска, но никогда не записываются в файлы plan или state, например пароль, полученный из secret manager. В Terraform 1.11 добавили write-only аргументы с суффиксом _wo, которые позволяют управляемым ресурсам принимать эти ephemeral-значения: провайдер отправляет секрет в API, но никогда его не сохраняет. Поскольку Terraform не видит сохранённое значение, для ротации вы увеличиваете сопутствующий аргумент version. Ещё более простой вариант, если платформа это поддерживает, — позволить сервису самому генерировать и хранить секрет, как RDS умеет с manage_master_user_password, и тогда Terraform его вообще не видит.
ephemeral "random_password" "db" {
length = 32
}
resource "aws_db_instance" "main" {
identifier = "app-prod"
engine = "postgres"
instance_class = "db.t4g.medium"
allocated_storage = 50
username = "app"
password_wo = ephemeral.random_password.db.result
password_wo_version = 1 # bump to rotate
}
10Защитные барьеры: validation, check, тесты и policy as code
В Terraform есть несколько уровней встроенных проверок. Блоки validation у переменных отклоняют некорректный ввод ещё до планирования, например неизвестное имя окружения или размер инстанса не из разрешённого списка. Preconditions и postconditions внутри lifecycle ресурса фиксируют допущения, которые должны выполняться, например что выбранный образ собран под нужную архитектуру. Блоки check выполняют проверки после apply, например HTTP-запрос к новому endpoint, и выдают предупреждения, ничего не блокируя. Команда terraform test с файлами, оканчивающимися на .tftest.hcl, запускает plan или apply на тестовых входных данных и проверяет результаты — так авторы модулей ловят регрессии. За пределами самого Terraform tflint находит ошибки, специфичные для провайдеров, сканеры вроде Checkov или Trivy отмечают небезопасные настройки, например открытые security group, а policy-движки, такие как OPA с Conftest или Sentinel в HCP Terraform, применяют правила организации к плану до apply.
variable "environment" {
type = string
validation {
condition = contains(["staging", "prod"], var.environment)
error_message = "environment must be staging or prod."
}
}
check "site_up" {
data "http" "health" { url = "https://app.example.com/healthz" }
assert {
condition = data.http.health.status_code == 200
error_message = "Health check did not return 200."
}
}
Реальные ситуации
State заблокирован, а никто ничего не запускает
Проблема
CI-задачу отменили посреди apply. Теперь каждый новый plan падает с ошибкой о том, что state заблокирован, и показывает lock ID, пользователя и время часовой давности.
Как решить
Сначала убедитесь, что запуск действительно остановился: проверьте CI-систему и спросите человека, указанного в блокировке. Никогда не снимайте блокировку, пока apply ещё может писать, потому что два одновременных писателя портят state. Затем выполните terraform force-unlock с lock ID из сообщения об ошибке. Поскольку apply был прерван, некоторые ресурсы могут существовать, но не быть полностью записаны, поэтому запустите terraform plan и внимательно его прочитайте: всё, что создано, но отсутствует в state, можно импортировать. Если что-то выглядит неправильно, проверьте историю версий state-бакета. Чтобы это не повторилось, настройте CI так, чтобы apply-задачи никогда не отменялись автоматически, — используйте concurrency group без cancel-in-progress.
План хочет заменить продакшен-базу
Проблема
Небольшой pull request, который поправил настройки базы, выдаёт план, по которому продакшен-база будет уничтожена и создана заново. Ревьюер чуть было его не одобрил.
Как решить
Остановитесь и найдите в плане строку с пометкой forces replacement: в ней указан ответственный аргумент, часто это версия движка, тип хранилища, identifier, subnet group или availability zone. Решите, действительно ли это изменение нужно. Часто нет, и решение — откатить его или провести через поддерживаемый путь обновления на месте, например minor upgrade движка. Если значение поменял другой инструмент или консоль, может подойти ignore_changes. Если замена действительно необходима, планируйте её как миграцию со снапшотом и окном даунтайма, а не как рядовой apply. Добавьте базе lifecycle prevent_destroy и CI-политику, которая блокирует планы с удалением критичных ресурсов.
Перевод инфраструктуры, созданной в консоли, под Terraform
Проблема
Компания два года работает на ресурсах, созданных вручную в консоли: VPC, серверы, база данных, DNS-зоны. Она хочет перейти на Terraform, ничего не пересоздавая и не вызывая даунтайма.
Как решить
Проведите инвентаризацию того, что есть, и решите, чем управлять, начиная с наименее рискованного слоя, например DNS. Напишите блоки import, которые связывают каждый существующий ID с адресом ресурса, затем запустите terraform plan -generate-config-out=generated.tf — он набросает конфигурацию по реальным ресурсам. Почистите сгенерированный код: замените захардкоженные ID ссылками, вынесите переменные и сгруппируйте всё в модули. Повторяйте, пока terraform plan не покажет отсутствие изменений — это доказывает, что код и реальность совпадают, — а затем выполните apply, чтобы записать импорт в state. Двигайтесь слой за слоем, с remote state и CI с самого начала. Напоследок уберите в продакшене доступ на запись через консоль, чтобы источником истины оставался код.
Шпаргалка
- Посмотреть drift, ничего не меняя
terraform plan -refresh-only- Снять зависшую блокировку (после проверки)
terraform force-unlock <LOCK_ID>- Сгенерировать конфиг для блоков import
terraform plan -generate-config-out=generated.tf- Принудительно пересоздать один ресурс
terraform plan -replace=digitalocean_droplet.web- Зафиксировать провайдеры для всех платформ CI и ноутбуков
terraform providers lock -platform=linux_amd64 -platform=darwin_arm64- Показать state одного ресурса
terraform state show digitalocean_droplet.web- Попробовать выражения интерактивно
terraform console- Запустить тесты модулей
terraform test- Обновить провайдеры в рамках ограничений
terraform init -upgrade- Нарисовать граф зависимостей
terraform graph | dot -Tsvg > graph.svg
Вопросы и ответы
Q1Что такое state в Terraform и почему он должен быть удалённым?
State — это запись Terraform о том, какой реальный ресурс соответствует каждому ресурсу в коде, вместе с его атрибутами и зависимостями. Terraform использует его, чтобы вычислять план и отслеживать то, что API провайдера не может легко описать. Локальный state-файл работает только для одного человека. Удалённый state, например в версионированном бакете S3 или в Terraform Cloud, даёт команде и CI единый источник правды, историю для восстановления после ошибок и блокировку, чтобы два apply не могли выполняться одновременно. Поскольку state может хранить чувствительные значения вроде паролей, его нужно шифровать, ограничивать к нему доступ и никогда не коммитить в Git.
Q2Чем terraform plan отличается от terraform apply?
Plan работает только на чтение. Он обновляет известное состояние реальных ресурсов, сравнивает его с конфигурацией и печатает нужные действия: создание, обновление на месте, замена или удаление. Ничего не меняется. Apply выполняет эти действия через API провайдеров и обновляет state-файл. Если запустить apply без сохранённого плана, он вычислит новый план и попросит подтверждения. В команде безопасная схема такая: запускать plan в CI на pull request, ревьюить его вместе с кодом, сохранять, а после мерджа применять ровно этот сохранённый план — так проверенные и выполненные изменения гарантированно совпадают.
Q3Что такое дрифт и как с ним бороться?
Дрифт — любое расхождение между реальной инфраструктурой и тем, что описывают конфигурация и state Terraform; обычно его вызывают ручные изменения в консоли, другой инструмент или смена значений по умолчанию у провайдера. terraform plan показывает его как изменения, которые Terraform хочет внести. Дальше решаете вы: если ручное изменение было правильным, обновите код, чтобы план стал пустым; если нет — сделайте apply, чтобы вернуть объявленное состояние. Чтобы дрифта было меньше, ограничьте права на запись в консоли в продакшене, проводите все изменения через pull request'ы и запускайте plan по расписанию в CI с алертом, если он не пустой. Некоторые команды используют refresh-only планы, чтобы изучить дрифт, прежде чем действовать.
Q4Что будет, если потерять state-файл?
Terraform больше не знает, какими реальными ресурсами он управляет. Запуск apply попытается создать всё заново, что приведёт к дубликатам или конфликтам имён. Восстановление — это либо возврат state из бэкапа (поэтому и важен удалённый state с версионированием), либо его пересборка через import. Современный Terraform поддерживает блоки import в конфигурации: вы объявляете, какой ID существующего ресурса соответствует какому адресу, проверяете это в плане и применяете. Для больших конфигураций это медленно, поэтому настоящий ответ — профилактика: версионированный зашифрованный удалённый state, ограниченный доступ, блокировка и никакого ручного редактирования state-файлов, кроме как через команды terraform state.
Q5Terraform, OpenTofu или Pulumi: как выбрать?
У Terraform самая большая экосистема, документация и рынок специалистов, а HCL хорошо читается эксплуатационщиками. С 2023 года он распространяется под Business Source License — для большинства компаний это нормально, но лицензия ограничивает создание конкурирующих продуктов, а HashiCorp теперь входит в IBM. OpenTofu — open-source форк под эгидой Linux Foundation, совместимый с большей частью кода и провайдеров Terraform, и он добавляет возможности вроде клиентского шифрования state; он подходит командам, которым нужна открытая лицензия. Pulumi позволяет писать инфраструктуру на TypeScript, Python или Go, и разработчикам это нравится из-за циклов, абстракций и unit-тестов. Я бы выбирал исходя из требований к лицензии, навыков команды и уже существующего кода.
Q6Terraform или Ansible?
Они решают задачи разных уровней и хорошо работают вместе. Terraform создаёт инфраструктуру через API: серверы, сети, балансировщики, DNS, базы данных, IAM. Он декларативный и хранит state, поэтому знает, что изменить или удалить. Ansible настраивает то, что работает внутри машин, через SSH: пакеты, пользователей, конфиги, сервисы — и он в основном процедурный и без состояния. Распространённый поток: Terraform создаёт сервер и его DNS-запись, затем Ansible или cloud-init его харденят и настраивают. С контейнерами большая часть работы Ansible переезжает в Docker-образы, и Terraform плюс контейнерная платформа закрывают большинство потребностей, оставляя Ansible базовую настройку серверов.
Вопросы уровня senior
S1Как структурировать Terraform для нескольких окружений и команд?
Разделяйте state по окружениям и по компонентам, чтобы ошибка в staging не могла задеть продакшен, а каждый план оставался маленьким и быстрым. Распространённая схема — переиспользуемые модули в одном месте, а затем корневая папка на каждое окружение и компонент, например prod/network, prod/database, prod/app, каждая со своим ключом backend, которая вызывает общие модули со значениями для конкретного окружения. Компоненты обмениваются значениями через outputs, читаемые с помощью terraform_remote_state, или, что лучше, через data sources или parameter store, сохраняя связи явными. Workspaces подходят для одинаковых копий, например короткоживущих preview-окружений, но их легко неправильно использовать для разделения prod и staging, потому что ошибочно выбранный workspace незаметен. Инструменты вроде Terragrunt или HCP Terraform stacks уменьшают повторение. Компромисс — множество маленьких state: больше координации для сквозных изменений, но гораздо меньший blast radius.
S2Как безопасно запускать Terraform в CI?
Планы — на каждый pull request, apply — только из main-ветки и никогда с ноутбуков для общих окружений. Аутентифицируйте CI через OIDC в короткоживущие облачные роли: роль преимущественно на чтение для plan и более сильная роль для apply, доступная только защищённой main-ветке или environment. На pull request запускайте fmt, validate, tflint, сканер безопасности и plan и публикуйте план комментарием, чтобы ревьюеры читали реальные изменения, а не только код. После merge применяйте сохранённый план из этого коммита либо перепланируйте и требуйте одобрения, если план изменился. Сериализуйте запуски для каждого state с помощью concurrency group и никогда не отменяйте идущий apply. Добавьте плановую проверку drift по расписанию. Платформы вроде HCP Terraform, Spacelift или Atlantis дают многое из этого из коробки.
S3Новая мажорная версия провайдера переименовывает ресурсы. Как обновиться?
Относитесь к этому как к проекту, а не к простому повышению версии. Прочитайте upgrade guide: в нём перечислены переименованные ресурсы, изменённые аргументы и удалённые значения по умолчанию; например, версия 5 провайдера Cloudflare переименовала несколько ресурсов и поменяла структуру многих атрибутов. Обновляйтесь в отдельной ветке через terraform init -upgrade и исправляйте конфигурацию, пока не пройдёт validate. Для переименованных типов ресурсов используйте блоки moved, если провайдер поддерживает перемещение между типами, или удалите старый адрес из state блоком removed и импортируйте тот же объект под новым адресом. Цель — план, в котором нет ни одной замены реальной инфраструктуры. Делайте это по одному state, начиная с наименее критичного окружения, и держите изменение lock-файла в том же pull request. Фиксация мажорных версий pessimistic-оператором гарантирует, что такие обновления происходят только осознанно.
Глоссарий
- Provider
- Плагин, который переводит ресурсы Terraform в API-вызовы одной платформы, например AWS или Cloudflare.
- Resource address
- Уникальный путь ресурса в конфигурации, например module.web.aws_instance.app["api"].
- State
- Запись Terraform, связывающая каждый адрес ресурса с реальным объектом, которым он управляет, и его атрибутами.
- Backend
- Место, где хранится и блокируется state, например локальный файл, S3-бакет или HCP Terraform.
- State lock
- Метка, которая не даёт двум запускам Terraform одновременно писать в один и тот же state.
- Drift
- Расхождения между реальной инфраструктурой и тем, что описано в конфигурации и state, часто из-за ручных изменений.
- Module
- Переиспользуемая папка с кодом Terraform со входными переменными и outputs, которая вызывается как функция.
- moved block
- Конфигурация, сообщающая Terraform, что ресурс сменил адрес, чтобы он был перемещён в state, а не пересоздан.
- Ephemeral value
- Значение, доступное во время запуска, но никогда не записываемое в файлы plan или state; используется для секретов.
- Saved plan
- План, записанный в файл через -out, чтобы apply выполнил ровно те изменения, которые прошли ревью.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.