Перейти к содержанию

Terragrunt для DRY-модулей Terraform

IaC · Terraform
Изучено

Проблема

На три окружения (dev, staging, prod) Terraform плодит три директории, в каждой — copy-paste main.tf, backend.tf, providers.tf. Изменение провайдера требует трёх почти идентичных PR. Бэкенд-конфиг разъезжается, terraform init случайно пишет state в чужое окружение. Всё пахнет, но пока работает.

Решение

Terragrunt — тонкая обёртка над Terraform, которая делает две вещи:

  1. DRY-конфигурация. Бэкенд, провайдеры, общие переменные описываются один раз в корневом terragrunt.hcl. Дочерние terragrunt.hcl их наследуют через include.
  2. Автоматическое определение бэкенда. Путь в S3/Azure Blob генерируется из пути в репозитории — перепутать окружения физически нельзя.

Пример

Структура:

infra/
├── terragrunt.hcl                 # корневой: remote state, провайдеры
├── modules/
│   └── vpc/
│       ├── main.tf
│       └── variables.tf
└── environments/
    ├── dev/
    │   └── vpc/terragrunt.hcl
    ├── staging/
    │   └── vpc/terragrunt.hcl
    └── prod/
        └── vpc/terragrunt.hcl

terragrunt.hcl в корне — определяется один раз:

remote_state {
  backend = "s3"
  generate = {
    path      = "backend.tf"
    if_exists = "overwrite_terragrunt"
  }
  config = {
    bucket         = "acme-tfstate"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "eu-central-1"
    encrypt        = true
    dynamodb_table = "acme-tfstate-lock"
  }
}

generate "providers" {
  path      = "providers.tf"
  if_exists = "overwrite_terragrunt"
  contents  = file("${get_terragrunt_dir()}/../../_shared/providers.tf")
}

environments/prod/vpc/terragrunt.hcl — весь окружение-специфичный код:

include "root" {
  path = find_in_parent_folders()
}

terraform {
  source = "../../../modules/vpc"
}

inputs = {
  cidr_block = "10.10.0.0/16"
  env        = "prod"
}

Запуск — как обычный Terraform, только через terragrunt:

cd environments/prod/vpc
terragrunt plan
terragrunt apply

# Прогнать все окружения разом
cd environments
terragrunt run-all plan

Когда применять

  • Окружений больше одного, конфиги уже дрейфуют.
  • Несколько команд делят одно IaC-репо.
  • Хочется запретить «прод случайно писал state в dev-бакет» на уровне инструмента, а не ревью.

Источник

Как применить у себя

  1. Выделить общий код из существующих окружений в modules/ и _shared/.
  2. Создать корневой terragrunt.hcl с remote_state и generate.
  3. Переписать каждое окружение на мини-terragrunt.hcl с include + inputs.
  4. Удалить руками дублирующиеся backend.tf/providers.tf из окружений.
  5. Прогон terragrunt run-all plan без изменений ресурсов = миграция прошла чисто → статус Изучено.