Что такое Terragrunt?

Terragrunt — это тонкий wrapper для Terraform, который предоставляет дополнительные инструменты для поддержания DRY (Don't Repeat Yourself) принципа, управления remote state и упрощения работы с Terraform в больших проектах. Terragrunt помогает организовать код Terraform более эффективно и избежать дублирования конфигураций.

Основные возможности Terragrunt

  • DRY principle — избежание дублирования кода через наследование
  • Remote state management — автоматическая настройка backend
  • Locking — автоматическая настройка state locking
  • Multiple environments — удобное управление разными окружениями
  • Dependencies — управление зависимостями между модулями
  • Hooks — выполнение команд до и после Terraform операций

Установка Terragrunt

Установить Terragrunt можно несколькими способами:

 1# macOS с Homebrew
 2brew install terragrunt
 3
 4# Linux - скачивание бинарного файла
 5wget https://github.com/gruntwork-io/terragrunt/releases/download/v0.54.8/terragrunt_linux_amd64
 6chmod +x terragrunt_linux_amd64
 7sudo mv terragrunt_linux_amd64 /usr/local/bin/terragrunt
 8
 9# Проверка установки
10terragrunt --version
11
12# Также потребуется Terraform
13terraform --version

Структура проекта с Terragrunt

 1infrastructure/
 2├── terragrunt.hcl                    # Корневая конфигурация
 3├── modules/                          # Terraform модули
 4│   ├── vpc/
 5│   │   ├── main.tf
 6│   │   ├── variables.tf
 7│   │   └── outputs.tf
 8│   └── ec2/
 9│       ├── main.tf
10│       ├── variables.tf
11│       └── outputs.tf
12└── environments/
13    ├── dev/
14    │   ├── terragrunt.hcl
15    │   ├── vpc/
16    │   │   └── terragrunt.hcl
17    │   └── ec2/
18    │       └── terragrunt.hcl
19    ├── staging/
20    │   ├── terragrunt.hcl
21    │   ├── vpc/
22    │   │   └── terragrunt.hcl
23    │   └── ec2/
24    │       └── terragrunt.hcl
25    └── prod/
26        ├── terragrunt.hcl
27        ├── vpc/
28        │   └── terragrunt.hcl
29        └── ec2/
30            └── terragrunt.hcl

Корневая конфигурация Terragrunt

 1# infrastructure/terragrunt.hcl
 2
 3# Настройка remote state для всех модулей
 4remote_state {
 5  backend = "s3"
 6  config = {
 7    bucket         = "my-terraform-state-bucket"
 8    key            = "${path_relative_to_include()}/terraform.tfstate"
 9    region         = "us-west-2"
10    encrypt        = true
11    dynamodb_table = "terraform-state-lock"
12  }
13  generate = {
14    path      = "backend.tf"
15    if_exists = "overwrite_terragrunt"
16  }
17}
18
19# Общий provider для всех модулей
20generate "provider" {
21  path      = "provider.tf"
22  if_exists = "overwrite_terragrunt"
23  contents  = <<EOF
24terraform {
25  required_providers {
26    aws = {
27      source  = "hashicorp/aws"
28      version = "~> 5.0"
29    }
30  }
31}
32
33provider "aws" {
34  region = var.aws_region
35  
36  default_tags {
37    tags = {
38      Environment   = var.environment
39      Project       = var.project_name
40      ManagedBy     = "Terragrunt"
41    }
42  }
43}
44EOF
45}
46
47# Общие переменные
48inputs = {
49  project_name = "my-project"
50}

Конфигурация окружения

 1# environments/dev/terragrunt.hcl
 2
 3# Наследование корневой конфигурации
 4include "root" {
 5  path = find_in_parent_folders()
 6}
 7
 8# Переменные для dev окружения
 9inputs = {
10  environment = "dev"
11  aws_region  = "us-west-2"
12  
13  # Настройки для dev
14  instance_type = "t3.micro"
15  min_size      = 1
16  max_size      = 2
17  desired_capacity = 1
18}

Конфигурация модуля

 1# environments/dev/vpc/terragrunt.hcl
 2
 3# Наследование конфигурации окружения
 4include "root" {
 5  path = find_in_parent_folders()
 6}
 7
 8include "env" {
 9  path = find_in_parent_folders("terragrunt.hcl")
10}
11
12# Указание на Terraform модуль
13terraform {
14  source = "../../../modules/vpc"
15}
16
17# Переменные специфичные для VPC
18inputs = {
19  vpc_cidr             = "10.0.0.0/16"
20  availability_zones   = ["us-west-2a", "us-west-2b"]
21  public_subnets       = ["10.0.1.0/24", "10.0.2.0/24"]
22  private_subnets      = ["10.0.10.0/24", "10.0.20.0/24"]
23  enable_nat_gateway   = true
24  single_nat_gateway   = true  # для dev экономим деньги
25}

Модуль с зависимостями

 1# environments/dev/ec2/terragrunt.hcl
 2
 3include "root" {
 4  path = find_in_parent_folders()
 5}
 6
 7include "env" {
 8  path = find_in_parent_folders("terragrunt.hcl")
 9}
10
11terraform {
12  source = "../../../modules/ec2"
13}
14
15# Зависимость от VPC модуля
16dependency "vpc" {
17  config_path = "../vpc"
18  
19  mock_outputs = {
20    vpc_id = "vpc-fake-id"
21    private_subnet_ids = ["subnet-fake-1", "subnet-fake-2"]
22  }
23}
24
25inputs = {
26  vpc_id            = dependency.vpc.outputs.vpc_id
27  subnet_ids        = dependency.vpc.outputs.private_subnet_ids
28  instance_type     = "t3.micro"
29  key_name          = "dev-key"
30  
31  user_data = <<-EOF
32    #!/bin/bash
33    yum update -y
34    yum install -y httpd
35    systemctl start httpd
36    systemctl enable httpd
37  EOF
38}

Основные команды Terragrunt

 1# Инициализация (аналог terraform init)
 2terragrunt init
 3
 4# Планирование (аналог terraform plan)
 5terragrunt plan
 6
 7# Применение (аналог terraform apply)
 8terragrunt apply
 9
10# Применение для всех модулей в директории
11terragrunt run-all apply
12
13# Планирование для всех модулей
14terragrunt run-all plan
15
16# Уничтожение ресурсов
17terragrunt destroy
18
19# Уничтожение всех ресурсов в директории
20terragrunt run-all destroy
21
22# Показать зависимости
23terragrunt graph-dependencies
24
25# Валидация конфигурации
26terragrunt validate

Hooks пример

 1# terragrunt.hcl с hooks
 2
 3terraform {
 4  source = "git::https://github.com/my-org/terraform-modules.git//vpc?ref=v1.0.0"
 5  
 6  before_hook "before_init" {
 7    commands     = ["init"]
 8    execute      = ["echo", "Initializing Terraform..."]
 9  }
10
11  after_hook "after_apply" {
12    commands     = ["apply"]
13    execute      = ["echo", "Terraform apply completed successfully!"]
14    run_on_error = false
15  }
16
17  after_hook "notify_slack" {
18    commands = ["apply"]
19    execute  = [
20      "curl", "-X", "POST",
21      "-H", "Content-type: application/json",
22      "--data", "{\"text\":\"Terraform deployment completed for ${get_env(\"ENVIRONMENT\", \"unknown\")} environment\"}",
23      get_env("SLACK_WEBHOOK_URL", "")
24    ]
25    run_on_error = false
26  }
27}

Когда использовать Terragrunt

  • Большие проекты с множественными окружениями
  • Необходимость избежать дублирования Terraform кода
  • Сложная структура зависимостей между модулями
  • Стандартизация настроек backend и provider
  • Автоматизация управления remote state
  • Необходимость в hooks для дополнительных действий

Преимущества Terragrunt

  • Соблюдение DRY принципа в Terraform коде
  • Автоматическая настройка remote state
  • Упрощенное управление множественными окружениями
  • Удобное управление зависимостями
  • Возможность выполнения команд для всех модулей сразу
  • Поддержка hooks для автоматизации

Ограничения Terragrunt

  • Дополнительный слой абстракции над Terraform
  • Необходимость изучения специфичного HCL синтаксиса
  • Может усложнить отладку проблем
  • Зависимость от внешнего инструмента
  • Менее популярен в некоторых командах

Рекомендации по использованию

Для эффективного использования Terragrunt рекомендуется:

  • Начать с простой структуры и постепенно усложнять
  • Создать четкую структуру директорий для окружений
  • Использовать семантическое версионирование для модулей
  • Документировать зависимости и структуру проекта
  • Настроить CI/CD пайплайны с учетом Terragrunt команд
  • Регулярно обновлять Terragrunt до новых версий

FAQ

Подходит ли Terragrunt для продакшена?

Да, Terragrunt активно используется в production средах крупных компаний для управления сложными Terraform проектами.

Можно ли использовать Terragrunt с существующим Terraform кодом?

Да, можно постепенно мигрировать существующий Terraform код на Terragrunt, начиная с настройки remote state и постепенно добавляя другие возможности.

Влияет ли Terragrunt на производительность?

Terragrunt добавляет минимальные накладные расходы, так как в основном генерирует Terraform файлы и передает управление самому Terraform.