Terragrunt ist ein leistungsstarkes Tool, das die Verwendung von Terraform erheblich vereinfacht und erweitert. Es ist eine dünne Wrapper-Lösung um Terraform, die DRY-Prinzipien (Don’t Repeat Yourself) in deine Infrastructure-as-Code-Praxis bringt und die Verwaltung komplexer, mehrschichtiger Terraform-Konfigurationen deutlich erleichtert.
In diesem umfassenden Guide erfährst du, was Terragrunt genau ist, wie es sich von Terraform unterscheidet und wie du es in deinen Projekten effektiv einsetzen kannst.
Was ist Terragrunt?
Terragrunt ist ein Open-Source-Tool, das als Wrapper um Terraform fungiert. Es wurde von Gruntwork entwickelt, um die häufigsten Probleme zu lösen, die Entwickler bei der Arbeit mit Terraform in größeren Projekten haben. Terragrunt ist keine Alternative zu Terraform, sondern eine Erweiterung, die Terraform-Befehle ausführt und dabei zusätzliche Funktionalitäten bietet.
Kernkonzept: Terragrunt als Terraform-Erweiterung
Terragrunt erweitert Terraform um folgende wichtige Features:
- DRY-Prinzipien: Eliminiert Code-Duplikation durch zentrale Konfigurationen
- Remote State Management: Automatische Verwaltung von Remote State Backends
- Dependency Management: Automatische Ausführung von Abhängigkeiten zwischen Modulen
- Konfigurationsvererbung: Wiederverwendbare Konfigurationen über mehrere Umgebungen
- Locking: Automatisches Locking von Remote State für sichere parallele Ausführungen
Warum Terragrunt?
Während Terraform bereits ein mächtiges Tool für Infrastructure as Code ist, stößt man bei größeren Projekten schnell an Grenzen:
Probleme mit reinem Terraform:
- Code-Duplikation zwischen Umgebungen (Dev, Staging, Production)
- Manuelle Verwaltung von Remote State Backends
- Schwierige Verwaltung von Abhängigkeiten zwischen Modulen
- Fehlende Wiederverwendbarkeit von Konfigurationen
- Komplexe Verzeichnisstrukturen für Multi-Environment-Setups
Terragrunt löst diese Probleme:
- Zentrale Konfigurationen, die von allen Umgebungen genutzt werden
- Automatische Backend-Konfiguration
- Einfache Verwaltung von Abhängigkeiten
- Klare, konsistente Verzeichnisstrukturen
Terragrunt vs. Terraform: Die Unterschiede
Es ist wichtig zu verstehen, dass Terragrunt kein Ersatz für Terraform ist, sondern eine Erweiterung:
| Feature | Terraform | Terragrunt |
|---|---|---|
| Infrastructure Definition | ✅ Ja | ❌ Nein (nutzt Terraform) |
| State Management | Manuell | ✅ Automatisch |
| DRY-Prinzipien | Begrenzt | ✅ Vollständig |
| Dependency Management | Manuell | ✅ Automatisch |
| Backend-Konfiguration | Manuell | ✅ Automatisch |
| Konfigurationsvererbung | ❌ Nein | ✅ Ja |
Terragrunt führt im Hintergrund Terraform-Befehle aus und fügt dabei zusätzliche Funktionalitäten hinzu. Du schreibst weiterhin Terraform-Code, aber Terragrunt hilft dir dabei, diesen Code besser zu organisieren und zu verwalten.
Installation von Terragrunt
Voraussetzungen
Bevor du Terragrunt installierst, stelle sicher, dass du folgende Tools installiert hast:
Installation über Homebrew (macOS/Linux)
Die einfachste Methode für macOS und Linux:
brew install terragrunt
Installation über den Paketmanager (Linux)
Für Ubuntu/Debian:
# Terragrunt Repository hinzufügen
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=$(dpkg --print-architecture)] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install terragrunt
Manuelle Installation
- Lade die neueste Version von der Terragrunt Releases-Seite herunter
- Extrahiere die Binärdatei
- Verschiebe sie in einen Verzeichnis, der in deinem
PATHist:
# Beispiel für Linux/macOS
wget https://github.com/gruntwork-io/terragrunt/releases/download/v0.54.0/terragrunt_linux_amd64
chmod +x terragrunt_linux_amd64
sudo mv terragrunt_linux_amd64 /usr/local/bin/terragrunt
Installation über Go (für Entwickler)
Falls du Go installiert hast:
go install github.com/gruntwork-io/terragrunt/cmd/terragrunt@latest
Installation überprüfen
Nach der Installation kannst du die Version überprüfen:
terragrunt --version
Die Ausgabe sollte etwa so aussehen:
terragrunt version v0.54.0
Erste Schritte mit Terragrunt
Projektstruktur erstellen
Terragrunt verwendet eine spezifische Verzeichnisstruktur, die das DRY-Prinzip unterstützt. Hier ist eine typische Struktur:
infrastructure/
├── terragrunt.hcl # Root-Konfiguration
├── environments/
│ ├── dev/
│ │ └── terragrunt.hcl
│ ├── staging/
│ │ └── terragrunt.hcl
│ └── prod/
│ └── terragrunt.hcl
└── modules/
└── vpc/
├── main.tf
├── variables.tf
└── outputs.tf
Erste terragrunt.hcl Datei
Erstelle eine terragrunt.hcl Datei in deinem Projektverzeichnis:
# terragrunt.hcl
terraform {
source = "../modules/vpc"
}
inputs = {
vpc_name = "my-vpc"
cidr_block = "10.0.0.0/16"
}
Diese Konfiguration:
- Verweist auf ein Terraform-Modul im
../modules/vpcVerzeichnis - Definiert Input-Variablen, die an das Modul übergeben werden
Terragrunt-Befehle ausführen
Terragrunt-Befehle sind fast identisch mit Terraform-Befehlen:
# Initialisierung
terragrunt init
# Plan ausführen
terragrunt plan
# Anwenden
terragrunt apply
# Zerstören
terragrunt destroy
Terragrunt führt diese Befehle intern mit Terraform aus und fügt dabei seine zusätzlichen Features hinzu.
Remote State Management
Eines der mächtigsten Features von Terragrunt ist das automatische Remote State Management.
Problem mit reinem Terraform
In reinem Terraform musst du für jede Umgebung manuell die Backend-Konfiguration definieren:
# dev/backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-dev"
key = "vpc/terraform.tfstate"
region = "us-east-1"
}
}
# prod/backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state-prod"
key = "vpc/terraform.tfstate"
region = "us-east-1"
}
}
Dies führt zu Code-Duplikation und Fehleranfälligkeit.
Lösung mit Terragrunt
Mit Terragrunt kannst du die Backend-Konfiguration zentral definieren:
# root terragrunt.hcl
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state-${get_env("ENVIRONMENT", "dev")}"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
}
}
Terragrunt generiert automatisch die richtige Backend-Konfiguration für jede Umgebung basierend auf dem aktuellen Pfad.
Dynamische State-Pfade
Terragrunt unterstützt dynamische State-Pfade basierend auf der Verzeichnisstruktur:
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Die Funktion path_relative_to_include() erstellt automatisch einen eindeutigen State-Pfad basierend auf der Verzeichnisstruktur.
DRY-Prinzipien mit Terragrunt
Konfigurationsvererbung
Terragrunt unterstützt Konfigurationsvererbung über mehrere Ebenen:
# root terragrunt.hcl
locals {
common_vars = {
region = "us-east-1"
environment = "dev"
}
}
# environments/dev/terragrunt.hcl
include "root" {
path = find_in_parent_folders()
}
terraform {
source = "../../modules/vpc"
}
inputs = merge(
include.root.locals.common_vars,
{
vpc_name = "dev-vpc"
cidr_block = "10.0.0.0/16"
}
)
Zentrale Konfigurationen
Du kannst gemeinsame Konfigurationen in einer zentralen Datei definieren:
# common.hcl
locals {
common_tags = {
Environment = "production"
ManagedBy = "terraform"
Team = "platform"
}
common_backend_config = {
bucket = "my-terraform-state"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Diese Konfiguration kann dann von allen Umgebungen genutzt werden.
Dependency Management
Terragrunt kann automatisch Abhängigkeiten zwischen Modulen verwalten.
Dependencies definieren
# vpc/terragrunt.hcl
terraform {
source = "../../modules/vpc"
}
dependencies {
paths = ["../networking"]
}
inputs = {
vpc_name = "my-vpc"
}
Automatische Ausführung
Wenn du terragrunt apply ausführst, führt Terragrunt automatisch zuerst terragrunt apply in den abhängigen Verzeichnissen aus:
terragrunt apply
# Terragrunt führt automatisch aus:
# 1. terragrunt apply in ../networking
# 2. terragrunt apply im aktuellen Verzeichnis
Abhängigkeiten mit Outputs
Terragrunt kann auch Outputs von abhängigen Modulen automatisch als Inputs verwenden:
# app/terragrunt.hcl
terraform {
source = "../../modules/app"
}
dependencies {
paths = ["../vpc"]
}
inputs = {
vpc_id = dependency.vpc.outputs.vpc_id
subnet_ids = dependency.vpc.outputs.subnet_ids
}
Praktisches Beispiel: Multi-Environment-Setup
Lass uns ein vollständiges Beispiel für ein Multi-Environment-Setup erstellen:
Verzeichnisstruktur
infrastructure/
├── terragrunt.hcl
├── environments/
│ ├── dev/
│ │ ├── terragrunt.hcl
│ │ └── vpc/
│ │ └── terragrunt.hcl
│ └── prod/
│ ├── terragrunt.hcl
│ └── vpc/
│ └── terragrunt.hcl
└── modules/
└── vpc/
├── main.tf
├── variables.tf
└── outputs.tf
Root-Konfiguration
# infrastructure/terragrunt.hcl
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state-${get_env("ENVIRONMENT", "dev")}"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
generate "provider" {
path = "provider.tf"
if_exists = "overwrite_terragrunt"
contents = <<EOF
provider "aws" {
region = var.aws_region
}
EOF
}
Environment-Konfiguration
# infrastructure/environments/dev/terragrunt.hcl
include "root" {
path = find_in_parent_folders()
}
locals {
environment = "dev"
aws_region = "us-east-1"
}
inputs = {
aws_region = local.aws_region
environment = local.environment
}
VPC-Modul-Konfiguration
# infrastructure/environments/dev/vpc/terragrunt.hcl
include "root" {
path = find_in_parent_folders("terragrunt.hcl")
}
include "env" {
path = find_in_parent_folders("environments/dev/terragrunt.hcl")
}
terraform {
source = "../../../modules/vpc"
}
inputs = {
vpc_name = "${include.env.locals.environment}-vpc"
cidr_block = "10.0.0.0/16"
tags = {
Environment = include.env.locals.environment
}
}
Terraform-Modul
# infrastructure/modules/vpc/main.tf
variable "vpc_name" {
description = "Name of the VPC"
type = string
}
variable "cidr_block" {
description = "CIDR block for the VPC"
type = string
}
variable "tags" {
description = "Tags to apply to resources"
type = map(string)
default = {}
}
resource "aws_vpc" "main" {
cidr_block = var.cidr_block
tags = merge(
var.tags,
{
Name = var.vpc_name
}
)
}
output "vpc_id" {
value = aws_vpc.main.id
}
Best Practices mit Terragrunt
1. Konsistente Verzeichnisstruktur
Verwende eine konsistente Verzeichnisstruktur für alle Projekte:
infrastructure/
├── terragrunt.hcl # Root-Konfiguration
├── environments/
│ ├── dev/
│ ├── staging/
│ └── prod/
└── modules/
├── vpc/
├── ec2/
└── rds/
2. Zentrale Konfigurationen nutzen
Definiere gemeinsame Konfigurationen in der Root-Konfiguration:
# root terragrunt.hcl
locals {
common_tags = {
ManagedBy = "terraform"
Team = "platform"
}
common_backend_config = {
bucket = "my-terraform-state"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
3. Environment-spezifische Konfigurationen
Verwende separate Konfigurationen für jede Umgebung:
# environments/dev/terragrunt.hcl
locals {
environment = "dev"
instance_type = "t3.micro"
}
# environments/prod/terragrunt.hcl
locals {
environment = "prod"
instance_type = "t3.large"
}
4. Dependencies explizit definieren
Definiere Abhängigkeiten explizit, um die Ausführungsreihenfolge zu kontrollieren:
dependencies {
paths = ["../vpc", "../networking"]
}
5. Inputs validieren
Validiere Inputs in deinen Terragrunt-Konfigurationen:
inputs = {
instance_count = 3
instance_type = "t3.micro"
}
# Validierung über Terraform-Variablen
6. Remote State Locking
Aktiviere immer State Locking für sichere parallele Ausführungen:
remote_state {
backend = "s3"
config = {
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks" # Wichtig für Locking
}
}
Häufige Probleme und Lösungen
Problem: Terragrunt findet Terraform nicht
Lösung: Stelle sicher, dass Terraform im PATH ist:
which terraform
# Falls nicht gefunden:
export PATH=$PATH:/path/to/terraform
Problem: State-Lock-Fehler
Lösung: Überprüfe, ob ein anderer Prozess den State lockt:
# State-Lock manuell entfernen (nur wenn sicher!)
terragrunt force-unlock <lock-id>
Problem: Dependencies werden nicht erkannt
Lösung: Stelle sicher, dass die dependencies Block korrekt definiert ist:
dependencies {
paths = ["../vpc"] # Relativer Pfad
}
Problem: Backend-Konfiguration wird nicht generiert
Lösung: Überprüfe die remote_state Konfiguration:
remote_state {
backend = "s3"
config = {
# Stelle sicher, dass alle erforderlichen Felder vorhanden sind
bucket = "my-terraform-state"
key = "${path_relative_to_include()}/terraform.tfstate"
region = "us-east-1"
}
}
Terragrunt vs. Terraform Workspaces
Viele Entwickler fragen sich, ob sie Terragrunt oder Terraform Workspaces verwenden sollen. Hier ist ein Vergleich:
| Feature | Terraform Workspaces | Terragrunt |
|---|---|---|
| State-Isolation | ✅ Ja | ✅ Ja |
| Code-Duplikation | ❌ Nein | ✅ Eliminiert |
| Backend-Konfiguration | Manuell | ✅ Automatisch |
| Dependency Management | ❌ Nein | ✅ Ja |
| Verzeichnisstruktur | Flach | ✅ Hierarchisch |
Empfehlung: Terragrunt ist besser für größere Projekte mit mehreren Umgebungen und komplexen Abhängigkeiten geeignet.
Fazit: Terragrunt als Terraform-Erweiterung
Terragrunt ist eine mächtige Erweiterung für Terraform, die Infrastructure as Code auf ein neues Level hebt. Es löst die häufigsten Probleme, die Entwickler bei größeren Terraform-Projekten haben:
- ✅ DRY-Prinzipien: Eliminiert Code-Duplikation durch zentrale Konfigurationen
- ✅ Automatisches State Management: Keine manuelle Backend-Konfiguration mehr
- ✅ Dependency Management: Automatische Ausführung von Abhängigkeiten
- ✅ Bessere Organisation: Klare, konsistente Verzeichnisstrukturen
- ✅ Wiederverwendbarkeit: Einfache Wiederverwendung von Konfigurationen
Terragrunt ist kein Ersatz für Terraform, sondern eine Erweiterung, die Terraform-Befehle ausführt und dabei zusätzliche Funktionalitäten bietet. Du schreibst weiterhin Terraform-Code, aber Terragrunt hilft dir dabei, diesen Code besser zu organisieren, zu verwalten und zu skalieren.
Wann sollte man Terragrunt verwenden?
Terragrunt ist besonders nützlich für:
- Multi-Environment-Setups (Dev, Staging, Production)
- Große Projekte mit vielen Modulen und Abhängigkeiten
- Teams, die DRY-Prinzipien in ihrer IaC-Praxis anwenden möchten
- Komplexe Infrastrukturen mit vielen Abhängigkeiten zwischen Komponenten
Wann reicht Terraform allein?
Reines Terraform reicht aus für:
- Kleine Projekte mit einer einzigen Umgebung
- Einfache Infrastrukturen ohne komplexe Abhängigkeiten
- Lernprojekte zum Verständnis der Terraform-Grundlagen
Nächste Schritte
Nach diesem Einstieg in Terragrunt kannst du:
- Terragrunt in deinen Projekten implementieren: Beginne mit einem kleinen Projekt und erweitere schrittweise
- Multi-Environment-Setups erstellen: Richte Dev, Staging und Production-Umgebungen ein
- Dependency Management nutzen: Organisiere deine Module mit Abhängigkeiten
- Best Practices anwenden: Implementiere DRY-Prinzipien und zentrale Konfigurationen
Weiterführende Ressourcen
Wenn du mehr über Terragrunt erfahren möchtest, empfehle ich dir folgende Ressourcen:
- Terragrunt Dokumentation - Offizielle Dokumentation mit allen Features
- Gruntwork Terragrunt Guide - GitHub Repository mit Beispielen
- Terraform Dokumentation - Grundlagen für Terraform
- Infrastructure as Code Best Practices - Best Practices für IaC
Benötigen Sie professionelle Infrastructure as Code Entwicklung?
Sie möchten Ihre Infrastruktur mit Terraform und Terragrunt verwalten oder benötigen Unterstützung bei der Einrichtung? Wir bieten professionelle Systemadministration und Systemintegration mit modernen IaC-Tools. Von der Planung bis zur Wartung – wir übernehmen die komplette Verantwortung für Ihre IT-Infrastruktur.
Viel Erfolg mit Terragrunt! 🚀