Warum die Terraform-Struktur zählt
Jedes Infrastruktur-Team beginnt gleich: mit einer einzigen main.tf-Datei, die ein paar Ressourcen provisioniert. Für einen Proof of Concept funktioniert das prima. Dann wächst das Projekt, mehr Engineers steigen ein, und plötzlich hat diese monolithische Datei 2.000 Zeilen, niemand weiß mehr, was wovon abhängt, und jedes terraform plan dauert acht Minuten.
Kommt Ihnen bekannt vor? Die Art und Weise, wie Sie Ihren Terraform-Code strukturieren, hat direkten Einfluss darauf, wie schnell Ihr Team liefern kann, wie sicher Sie Änderungen umsetzen können und wie leicht neue Engineers eingearbeitet werden. In diesem Leitfaden teilen wir die Patterns, die wir bei DevOpsVibe über Dutzende Produktionsumgebungen hinweg einsetzen.
Die modulbasierte Architektur
Die wichtigste Einzelentscheidung, die Sie treffen können, ist, früh eine modulbasierte Architektur einzuführen. Module sind wiederverwendbare, testbare Infrastruktur-Einheiten, die eine logische Gruppierung von Ressourcen kapseln.
Verzeichnisstruktur
Dies ist die Struktur, die wir für mittlere bis große Projekte empfehlen:
infrastructure/
├── modules/
│ ├── networking/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── outputs.tf
│ │ └── README.md
│ ├── compute/
│ ├── database/
│ └── monitoring/
├── environments/
│ ├── dev/
│ │ ├── main.tf
│ │ ├── variables.tf
│ │ ├── terraform.tfvars
│ │ └── backend.tf
│ ├── staging/
│ └── production/
├── global/
│ ├── iam/
│ └── dns/
└── terragrunt.hcl # optional
Jedes Environment-Verzeichnis komponiert Module mit umgebungsspezifischen Variablen. Die Module selbst enthalten keine fest eingebauten Werte.
Ein wiederverwendbares Modul schreiben
Ein gut strukturiertes Modul hat klare Inputs, Outputs und eine einzige Verantwortlichkeit:
# modules/networking/variables.tf
variable "vpc_cidr" {
description = "CIDR block for the VPC"
type = string
validation {
condition = can(cidrnetmask(var.vpc_cidr))
error_message = "Must be a valid CIDR block."
}
}
variable "environment" {
description = "Environment name (dev, staging, production)"
type = string
}
variable "availability_zones" {
description = "List of AZs to use"
type = list(string)
}
# modules/networking/main.tf
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.environment}-vpc"
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_subnet" "private" {
count = length(var.availability_zones)
vpc_id = aws_vpc.main.id
cidr_block = cidrsubnet(var.vpc_cidr, 8, count.index)
availability_zone = var.availability_zones[count.index]
tags = {
Name = "${var.environment}-private-${var.availability_zones[count.index]}"
Environment = var.environment
Type = "private"
}
}
# modules/networking/outputs.tf
output "vpc_id" {
description = "ID of the created VPC"
value = aws_vpc.main.id
}
output "private_subnet_ids" {
description = "List of private subnet IDs"
value = aws_subnet.private[*].id
}
State-Management-Strategie
Remote State ist für Teams nicht verhandelbar. Nutzen Sie S3 mit DynamoDB-Locking (AWS) oder GCS mit Locking (GCP):
# environments/production/backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "production/networking/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
Schlüsselregeln für State Management:
- Eine State-Datei pro Komponente und Umgebung. Legen Sie niemals Ihre gesamte Infrastruktur in einer einzigen State-Datei ab. Wenn Ihr VPC-State korrumpiert wird, soll er nicht Ihre Datenbank mit in den Abgrund reißen.
- Encryption at Rest aktivieren. State-Dateien enthalten sensible Daten, darunter Passwörter und Private Keys.
- State-Locking nutzen. Ohne es können zwei Engineers, die gleichzeitig
terraform applyausführen, Ihren State korrumpieren. - State-Dateien niemals in die Versionskontrolle einchecken. Fügen Sie
*.tfstateund*.tfstate.backupzu Ihrer.gitignorehinzu.
Variablen-Management
Vermeiden Sie hart einkodierte Werte. Nutzen Sie einen mehrschichtigen Ansatz:
# environments/production/terraform.tfvars
environment = "production"
vpc_cidr = "10.0.0.0/16"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
instance_type = "m6i.xlarge"
min_capacity = 3
max_capacity = 10
Für Secrets gilt: niemals in .tfvars-Dateien ablegen. Referenzieren Sie sie stattdessen aus einem Secrets Manager:
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "production/database/master-password"
}
resource "aws_db_instance" "main" {
password = data.aws_secretsmanager_secret_version.db_password.secret_string
# ...
}
Tagging-Strategie
Konsistentes Tagging ist essenziell für Kostenallokation, Security-Auditing und Ressourcenmanagement. Definieren Sie ein gemeinsames Tagging-Modul:
# modules/tags/main.tf
variable "environment" { type = string }
variable "project" { type = string }
variable "team" { type = string }
locals {
common_tags = {
Environment = var.environment
Project = var.project
Team = var.team
ManagedBy = "terraform"
Repository = "github.com/mycompany/infrastructure"
}
}
output "tags" {
value = local.common_tags
}
Und nutzen Sie es überall:
module "tags" {
source = "../../modules/tags"
environment = "production"
project = "platform"
team = "infrastructure"
}
resource "aws_instance" "app" {
# ...
tags = merge(module.tags.tags, {
Name = "app-server"
Role = "application"
})
}
CI/CD-Integration
Terraform sollte in der Produktion niemals vom Laptop eines Entwicklers aus laufen. Setzen Sie eine Pipeline auf:
- Pull Request wird geöffnet --
terraform fmt -checkundterraform validatelaufen automatisch - PR wird genehmigt --
terraform planläuft und die Ausgabe wird als PR-Kommentar gepostet - PR wird in main gemergt --
terraform apply -auto-approvewird in der Pipeline ausgeführt
Verwenden Sie Tools wie Atlantis oder Spacelift für diesen Workflow oder bauen Sie Ihren eigenen mit GitHub Actions:
# .github/workflows/terraform.yml
name: Terraform
on:
pull_request:
paths: ['infrastructure/**']
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init
working-directory: infrastructure/environments/production
- run: terraform plan -no-color -out=tfplan
working-directory: infrastructure/environments/production
- uses: actions/github-script@v7
with:
script: |
const output = require('fs').readFileSync('tfplan.txt', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## Terraform Plan\n\`\`\`\n${output}\n\`\`\``
});
Ihre Infrastruktur testen
Nutzen Sie Terratest oder terraform test (eingebaut seit Terraform 1.6), um Ihre Module zu validieren:
# modules/networking/tests/vpc.tftest.hcl
run "creates_vpc_with_correct_cidr" {
command = plan
variables {
vpc_cidr = "10.0.0.0/16"
environment = "test"
availability_zones = ["us-east-1a"]
}
assert {
condition = aws_vpc.main.cidr_block == "10.0.0.0/16"
error_message = "VPC CIDR block did not match expected value"
}
}
Häufige Anti-Patterns, die es zu vermeiden gilt
- Monolithische State-Dateien. Splitten Sie nach Komponente und Umgebung.
countverwenden, wofor_eachbesser passt.for_eachmit Maps liefert stabile Ressourcen-Adressen, die sich nicht verschieben, wenn Einträge hinzugefügt oder entfernt werden.- Drift ignorieren. Lassen Sie
terraform planregelmäßig laufen, um manuelle Änderungen zu erkennen. terraform fmtüberspringen. Erzwingen Sie Formatierung in CI. Inkonsistente Formatierung erzeugt laute Diffs.- Provider-Versionen fest einkodieren. Pinnen Sie sie explizit, aber prüfen Sie Updates regelmäßig.
Fazit
Terraform von Anfang an gut zu strukturieren, spart später exponentiellen Aufwand. Die oben beschriebenen Patterns -- modulbasierte Architektur, isolierter State, geschichtete Variablen, CI/CD-Automatisierung und Tests -- bilden das Fundament jedes skalierbaren Infrastruktur-Projekts, das wir liefern.
Bei DevOpsVibe helfen wir Teams, Terraform-Architekturen zu designen und umzusetzen, die von einer Handvoll Ressourcen auf Tausende skalieren. Ob Sie frisch starten oder eine bestehende Codebasis entwirren – unsere Engineers bringen Ihre Infrastruktur auf solides Fundament. Nehmen Sie Kontakt mit uns auf, um mehr zu erfahren.