Урок по треку DevOps: CI/CD, IaC, облака 8 мин

Terraform и IaC за 8 минут

Провайдеры и ресурсы, state и блокировки, plan и apply, модули, import, drift и работа в команде.

Infrastructure as Code (IaC): инфраструктура описывается файлами в git, а инструмент создаёт и меняет её по описанию. Плюсы: воспроизводимость, ревью изменений, история, одинаковые окружения. Terraform самый популярный инструмент для облачной инфраструктуры. С 2023 года он распространяется под лицензией BSL, и сообщество сделало открытый форк OpenTofu с почти тем же синтаксисом и командами.

Основные понятия

terraform {
  required_version = ">= 1.6"
  required_providers {
    yandex = {
      source  = "yandex-cloud/yandex"
      version = "~> 0.130"
    }
  }
  backend "s3" { ... }   # где хранить state
}

variable "env" { type = string }

locals {
  name = "api-${var.env}"
}

resource "yandex_compute_instance" "api" { ... }   # что создать

data "yandex_compute_image" "ubuntu" {             # что прочитать
  family = "ubuntu-2404-lts"
}

output "ip" { value = yandex_compute_instance.api.network_interface[0].nat_ip_address }
  • Provider: плагин для API облака или сервиса (AWS, Yandex Cloud, Kubernetes, GitHub).
  • Resource: объект, которым Terraform управляет.
  • Data source: объект, который Terraform только читает.
  • Variable, local, output: входы, внутренние вычисления, выходы.

Версии провайдеров фиксируются в .terraform.lock.hcl, его коммитят в git.

Цикл работы

  1. terraform init: скачать провайдеры и модули, подключить backend.
  2. terraform fmt и terraform validate: форматирование и проверка синтаксиса.
  3. terraform plan -out=tfplan: показать, что изменится, и сохранить план.
  4. terraform apply tfplan: применить ровно сохранённый план.

В плане значки: + создать, ~ изменить на месте, - удалить, -/+ пересоздать (удалить и создать, «must be replaced»). Пересоздание базы данных из-за смены неизменяемого поля это классический способ потерять прод, поэтому план читают внимательно.

State

Terraform хранит в state соответствие «ресурс в коде, объект в облаке» и последние известные атрибуты. Без state он не знает, что уже создал.

  • Хранить state удалённо (S3-совместимое хранилище, Terraform Cloud, Postgres), а не в локальном файле.
  • Включить блокировку, чтобы два apply не шли одновременно. Классика AWS: S3 плюс DynamoDB; в новых версиях S3-бэкенд умеет блокировку файлом в бакете (use_lockfile). В Yandex Cloud: Object Storage и YDB.
  • Включить версионирование бакета: испорченный state можно вернуть.
  • State содержит секреты в открытом виде (пароли, ключи), даже если переменная помечена sensitive. Доступ к нему ограничивают и шифруют.

Команды работы со state: terraform state list, state show, state mv (переименовать адрес без пересоздания), state rm (забыть ресурс, не удаляя в облаке). Вместо state mv теперь удобнее блок moved, вместо ручного terraform import блок import: оба проходят через план и ревью.

Drift

Дрейф: кто-то поменял ресурс руками в консоли облака. terraform plan покажет разницу и предложит вернуть как в коде. terraform plan -refresh-only показывает только изменения в облаке и позволяет принять их в state. Дрейф ловят регулярным plan по расписанию в CI.

Модули

Модуль это каталог с .tf файлами, который вызывают с параметрами:

module "vpc" {
  source = "./modules/vpc"
  cidr   = "10.10.0.0/16"
}

Модули дают переиспользование (одна сеть для dev и prod с разными параметрами). Версию внешнего модуля фиксируют (?ref=v1.2.0 или version).

count и for_each

count = 3 создаёт ресурсы с адресами [0], [1], [2]. Если удалить элемент из середины списка, индексы сдвинутся, и Terraform пересоздаст соседей. for_each по множеству или мапе адресует ресурсы ключами (["api"], ["web"]), удаление одного не задевает остальные.

lifecycle

  • prevent_destroy = true: план с удалением ресурса упадёт. Для баз и бакетов с данными.
  • create_before_destroy = true: при пересоздании сначала новый, потом удаление старого.
  • ignore_changes = [tags]: не трогать поле, которое меняет кто-то другой.

Окружения

Варианты: отдельные каталоги или state на каждое окружение (envs/dev, envs/prod) с общими модулями, либо workspaces. Для сильно различающихся окружений и разных прав доступа чаще выбирают отдельные каталоги и state: ошибка в dev не заденет prod.

Terraform в команде

  • Plan в merge request, apply только после ревью и из CI (Atlantis, GitLab, Terraform Cloud).
  • Никаких ручных изменений в консоли.
  • Небольшие state: один огромный state медленный и опасный.
  • В России registry.terraform.io доступен не всегда; используют зеркала провайдеров (у Yandex Cloud есть своё) через ~/.terraformrc.

Частые ошибки

  • Локальный state на ноутбуке и два человека с разными версиями.
  • apply без сохранённого плана: применится не то, что смотрели на ревью.
  • count по списку, который меняется.
  • Пароли в .tf и в git.
  • Игнорировать -/+ в плане.

Что спросят на собесе

  • Что такое state, где его хранить и зачем блокировка.
  • Как импортировать существующий ресурс и как переименовать ресурс без пересоздания.
  • Что такое drift и как его обнаружить.
  • Разница count и for_each.
  • Как организовать Terraform для нескольких окружений и команды.

Закрепите за 5 минут

После урока в тренажёре 3-5 проверочных вопросов, дальше модуль уходит в повторения.