Баннер мобильный (3) Пройти тест

Terraform: инфраструктура как код — с чего начать и как не убить прод

Разбираем модули и лучшие практики для надежной автоматизации ресурсов через Terraform

Разбор

16 апреля 2026

Поделиться

Скопировано
Terraform: инфраструктура как код — с чего начать и как не убить прод

Содержание

    Правильная работа с Terraform — это не просто написать код, а выстроить процесс — от создания модулей до CI/CD. В этой статье разберем, как начать, ничего не сломать и потом это нормально масштабировать.

    Что такое Terraform и зачем он нужен

    Terraform — это инструмент для управления инфраструктурой проекта как кодом от HashiCorp. Он позволяет управлять облачными и локальными ресурсами через декларативные конфигурационные файлы. С этим инструментом можно описывать, версионировать и безопасно разворачивать инфраструктуру любого масштаба.

    Принцип декларативного подхода: «что», а не «как»

    В отличие от императивных инструментов, где вы пишете пошаговые инструкции, в Terraform вы описываете желаемое состояние:

    # Мы говорим: "нужна виртуальная машина с такими параметрами" resource "yandex_compute_instance" "web" {   name        = "prod-web-01"   platform_id = "standard-v3"      resources {     cores  = 2     memory = 4   }      # Terraform сам решит, как ее создать, где разместить и какие зависимости учесть }

    Сравнение с другими инструментами

    Инструмент
    Назначение
    Когда выбирать
    Terraform
    Provisioning: создание и управление ресурсами
    Когда нужно управлять инфраструктурой в нескольких облаках или гибридной среде
    Ansible
    Configuration Management: настройка ОС и приложений
    Когда серверы уже созданы, и нужно установить ПО, настроить конфиги
    Pulumi
    IaC на привычных языках (Python, Go, TS)
    Если команда не хочет учить HCL и предпочитает императивный код
    CloudFormation
    IaC только для AWS
    Если вы работаете исключительно в экосистеме AWS

    Terraform не заменяет Ansible. Часто их используют вместе: Terraform создает виртуальные машины, Ansible настраивает программное обеспечение внутри.

    Terraform — идеальный выбор, если:

    • вы используете нескольких облачных провайдеров в связке (AWS + Yandex Cloud + on-prem);
    • команда хочет версионировать инфраструктуру как код;
    • нужно быстро поднимать/уничтожать окружения (dev/stage/prod);
    • нужно проводить аудит изменений — то есть смотреть, кто, когда и что поменял.

    Быстрый старт: как установить Terraform и создать первый ресурс

    Установить Terraform легко. Для этого используйте следующие команды.

    Для macOS:

    brew install terraform

    Для Linux (Ubuntu/Debian):

    sudo apt update && sudo apt install -y terraform

    Для Windows:

    choco install terraformс

    Проверьте установку. Для этого введите в командной строке:

    terraform version
    # В ответ увидите сообщение # Terraform v1.9.0

    Настройка провайдера (на примере Yandex Cloud)

    1. Создайте сервисный аккаунт в консоли Yandex Cloud.
    2. Получите access_key и secret_key.
    3. Создайте файл provider.tf:
    terraform {   required_providers {     yandex = {       source  = "yandex-cloud/yandex"       version = "0.120.0"  # Фиксируем версию!     }   } }
    provider "yandex" {   cloud_id  = var.cloud_id   folder_id = var.folder_id   zone      = "ru-central1-a"      # Секреты — только через переменные окружения!   service_account_key_file = var.sa_key_file }

    Три команды Terraform, которые нужно запомнить

    Команда
    Что делает
    Когда использовать
    terraform init
    Инициализирует проект, скачивает провайдеры
    Первый запуск или после добавления нового провайдера
    terraform plan
    Показывает, что изменится, без применения
    Перед каждым apply, в CI для ревью
    terraform apply
    Применяет изменения к инфраструктуре
    После утверждения плана, в продакшене — с manual approval

    Пример: поднимаем виртуальную машину с переменными через Terraform

    variables.tf:

    variable "instance_name" {   type        = string   description = "Имя виртуальной машины"   default     = "web-server" }
    variable "instance_cores" {   type        = number   description = "Количество CPU-ядер"   default     = 2 }

    main.tf:

    resource "yandex_compute_instance" "web" {   name        = var.instance_name   platform_id = "standard-v3"      resources {     cores  = var.instance_cores     memory = var.instance_cores * 2  # Логика: памяти в 2 раза больше ядер   }      boot_disk {     initialize_params {       image_id = "fd8k7m2p5q3r8t9v0w1x"  # Ubuntu 22.04 LTS       size     = 20     }   }      network_interface {     subnet_id = var.subnet_id     nat       = true  # Публичный IP   } }

    Запуск:

    terraform init terraform plan -out=tfplan terraform apply tfplan  # Или просто `apply`, но с файлом безопаснее

    Совет: Всегда используйте -out=tfplan, чтобы применить ровно тот план, который вы проверили.

    Язык HCL: синтаксис, который понятен человеку

    HashiCorp Configuration Language (HCL) создан так, чтобы его читали и люди, и машины. Разберем основные команды в Terraform, которые необходимы для работы.

    Базовые блоки: resource, variable, output

    # resource — что создаем resource "yandex_compute_instance" "app" { ... }
    # variable — что настраиваем извне variable "env" { type = string }
    # output — что показываем после применения output "app_public_ip" {   value = yandex_compute_instance.app.network_interface.0.ip_address }

    Работа с переменными: var, locals, tfvars

    Тип
    Синтаксис
    Когда использовать
    var.name
    var.instance_name
    Пользовательские параметры, передаются при запуске
    local.name
    local.full_name = «
    var.prefix
    var.prefix−{var.suffix}»
    Внутренние вычисления, не выносятся наружу
    terraform.tfvars
    Файл со значениями instance_name = «prod-web»
    Хранение значений для окружений (добавьте в .gitignore!)

    Полезные функции HCL

    # Условное создание ресурса resource "yandex_compute_instance" "debug" {   count = var.enable_debug ? 1 : 0  # Создастся, только если флаг включен   # ... }
    # Динамическое создание нескольких ресурсов resource "yandex_compute_instance" "workers" {   for_each = toset(var.worker_names)  # Список имен из переменной      name = "worker-${each.key}"   # ... }
    # Валидация входных данных variable "instance_type" {   type = string   validation {     condition     = contains(["small", "medium", "large"], var.instance_type)     error_message = "Допустимые значения: small, medium, large."   } }

    Валидация и форматирование кода

    terraform fmt -recursive  # Приводит код к единому стилю terraform validate        # Проверяет синтаксис и ссылки tflint                    # Сторонний линтер с доп. правилами

    Не храните секреты в .tf-файлах. Используйте переменные окружения (TF_VAR_…) или HashiCorp Vault.

    Модули Terraform: как писать код, который переиспользуется

    Модуль Terraform — как LEGO-блок: собрал один раз, протестировал — и используешь везде. Без дублирования кода и риска забыть важный параметр.

    Структура модуля Terraform: три файла, которые решают все

    Файл
    Назначение
    Пример
    main.tf
    Логика создания ресурсов
    resource «yandex_vpc_subnet» «private» { … }
    variables.tf
    Входные параметры
    variable «cidr» { type = string }
    outputs.tf
    Что возвращаем после создания
    output «subnet_id» { value = yandex_vpc_subnet.private.id }

    Дополнительно:

    • README.md — документация для пользователей модуля;
    • versions.tf — версии провайдеров и Terraform;
    • examples/ — примеры использования.

    Источники модулей: откуда брать и как подключать

    # Локальный модуль (для внутренних библиотек) module "network" {   source = "./modules/vpc"   # ... }
    # Git-репозиторий (внутренний или публичный) module "database" {   source = "git@github.com:company/terraform-modules.git//postgres?ref=v2.1.0"   # ... }
    # Официальный Registry (HashiCorp или облачных провайдеров) module "k8s" {   source  = "terraform-aws-modules/eks/aws"   version = "19.15.0"  # Всегда фиксируйте версию!   # ... }

    Пример: модуль для создания VPC с подсетями

    modules/vpc/main.tf:

    resource "yandex_vpc_network" "this" {   name = var.name   description = var.description }
    resource "yandex_vpc_subnet" "private" {   count = length(var.private_cidrs)      name           = "${var.name}-private-${count.index + 1}"   network_id     = yandex_vpc_network.this.id   zone           = var.azs[count.index]   v4_cidr_blocks = [var.private_cidrs[count.index]]   private        = true }
    resource "yandex_vpc_subnet" "public" {   count = length(var.public_cidrs)      name           = "${var.name}-public-${count.index + 1}"   network_id     = yandex_vpc_network.this.id   zone           = var.azs[count.index]   v4_cidr_blocks = [var.public_cidrs[count.index]] }

    Использование модуля:

    module "prod_vpc" {   source = "./modules/vpc"      name        = "prod-network"   description = "VPC для продакшен-окружения"      azs             = ["ru-central1-a", "ru-central1-b"]   private_cidrs   = ["10.0.1.0/24", "10.0.2.0/24"]   public_cidrs    = ["10.0.101.0/24", "10.0.102.0/24"]      tags = {     Environment = "production"     Team        = "platform"   } }

    Всегда фиксируйте версию модуля (version = «x.y.z» или ref=v2.1.0). Использование latest — риск, что завтра обновление сломает ваш план.

    Управление состоянием: почему terraform.tfstate так важен

    State-файл — это «чертеж» вашей инфраструктуры. Terraform сравнивает желаемое (код) с фактическим (state), чтобы понять, что изменить.

    Почему нельзя хранить state локально

    Проблема
    Последствие
    Решение
    Потеря файла
    Terraform «забудет» ресурсы, начнет создавать дубли
    Remote backend с бэкапами
    Конфликт версий
    Два инженера одновременно запустят apply — данные повредятся
    State locking (DynamoDB, Yandex Lock)
    Секреты в state
    Пароли, ключи могут попасть в репозиторий
    Шифрование на стороне хранилища + доступ по ролям

    Настройка remote backend (на примере Yandex Object Storage)

    terraform {   backend "s3" {     endpoint   = "storage.yandexcloud.net"     bucket     = "my-terraform-state"     key        = "prod/terraform.tfstate"     region     = "ru-central1"          # Блокировка через Yandex Lock     dynamodb_table = "terraform-locks"          # Шифрование     encrypt = true   } }

    Никогда не коммитьте terraform.tfstate в Git. Добавьте его в .gitignore вместе с *.tfvars, .terraform/

    Workspaces vs папки: как разделять окружения

    Вариант 1: Workspaces (проще, но менее изолированно)

    terraform workspace new dev terraform workspace new prod terraform workspace select prod terraform apply  # Применит к prod

    Вариант 2: Отдельные папки (рекомендуется)

    environments/ ├── dev/ │   ├── backend.tf │   ├── main.tf │   └── terraform.tfvars ├── stage/ └── prod/

    Для сложных проектов используйте папки + модули. Workspaces удобны для личных тестов, но в команде лучше явное разделение

    Лучшие практики Terraform для продакшена

    Terraform, как и любой удобный инструмент, имеет свои уязвимости и сложности в использовании. Чтобы избежать потери важных данных или взлома, применяйте следующие правила.

    Безопасность и контроль доступа

    • Секреты — только через переменные окружения или Vault.
    • IAM-роли с принципом наименьших привилегий.
    • Шифрование state-файлов на стороне хранилища.
    • Аудит: кто и когда запускал apply (через Cloud Logging).

    Чек-лист перед terraform apply в продакшен

    • Состояние хранится в remote backend с шифрованием.
    • Используется terraform plan -out=tfplan и ревью перед применением.
    • Секреты не закоммичены, используются через env/Vault.
    • Модули версионированы, не используется latest.
    • Запущено статическое сканирование кода (tfsec, Checkov).
    • Есть откатный план, который описывает, как быстро отменить изменения.
    • Уведомления о изменениях настроены (Slack, Telegram).

    Частые ошибки и как их избежать

    Ошибка
    Почему происходит
    Как исправить
    «Дрейф конфигурации»: ручные правки в консоли
    Нет процесса: все должно идти через Terraform
    Включите prevent_destroy в lifecycle, настройте уведомления об изменениях
    Конфликты состояния: два apply одновременно
    Локальный state, нет locking
    Используйте remote backend с state locking (S3+DynamoDB, Yandex Lock)
    Секреты в коде: access_key = «AKIA…»
    Удобно, но небезопасно
    Переменные окружения + Vault + .gitignore для *.tfvars
    Монолитный main.tf на 1000+ строк
    Не разбили на модули вовремя
    Выделите сетевую часть, БД, приложения в отдельные модули
    Игнорирование plan: применили «на глаз»
    Спешка, недоверие к инструменту
    Сделайте plan обязательным шагом в CI с manual approval
    Удаление ресурсов по ошибке
    Опечатка в count, for_each
    Используйте terraform state mv для переименования, а не пересоздания

    Как отменить опасные изменения

    # 1. Если еще не применили — просто удалите tfplan rm tfplan
    # 2. Если применили, но нужно откатить: #    а) Верните код к предыдущей версии в Git #    б) Запустите `terraform apply` — Terraform приведет инфраструктуру к желаемому состоянию
    # 3. Если удалили критический ресурс по ошибке: terraform state list  # Посмотреть, что «видит» Terraform terraform import <resource> <id>  # Вернуть ресурс под управление

    Terraform: коротко о главном

    • Terraform — инструмент для декларативного описания инфраструктуры: вы пишете, «что нужно», а он решает, «как сделать».
    • Старт прост: init → plan → apply. Но продакшен требует больше — модули, remote state, CI/CD.
    • Модули — основа масштабируемости. Пишите их как библиотеки —: с переменными, выводами и документацией.
    • Состояние (state) — критический артефакт. Храните удаленно, блокируйте при изменениях, делайте бэкапы.
    • Безопасность: секреты — только через env/Vault, код — сканируйте (tfsec, Checkov), права — по принципу наименьших привилегий.
    • Автоматизация: terraform plan в CI, manual approval перед apply, destroy — только с подтверждением.
    • Главное правило: пишите код для людей. Комментируйте, документируйте, тестируйте изменения через plan.

    Разбор

    Поделиться

    Скопировано
    0 комментариев
    Комментарии