Terraform-Patterns für die Teamzusammenarbeit
Workspaces, Remote State, Module-Registries und Review-Workflows – die Patterns, die Terraform beherrschbar halten, wenn ein ganzes Team mitarbeitet.

Terraform funktioniert gut, wenn ein einzelner Entwickler ein kleines Projekt betreut. Sobald ein ganzes Team gleichzeitig an der Infrastruktur arbeitet, wird alles, was für eine Person funktioniert hat, zur Konfliktquelle: beschädigte State-Dateien, auseinanderlaufende Umgebungen und undokumentierte Änderungen an Ressourcen. Diese Patterns adressieren genau die Zusammenarbeitsprobleme, die auftreten, sobald Infrastruktur zur Aufgabe eines ganzen Teams wird.
State-Isolation
Die häufigste Ursache für Terraform-Katastrophen im Team ist gemeinsam genutzter State ohne saubere Isolation. Ein Entwickler führt terraform apply in der Produktionsumgebung aus, während ein anderer gerade Änderungen testet – und beide schreiben in dieselbe State-Datei.
# ❌ Single state file for all environments
terraform {
backend "s3" {
bucket = "terraform-state"
key = "terraform.tfstate" # One file for everything
region = "us-east-1"
}
}
# ✅ Separate state per environment
# infrastructure/environments/production/backend.tf
terraform {
backend "s3" {
bucket = "terraform-state"
key = "production/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}
# infrastructure/environments/staging/backend.tf
terraform {
backend "s3" {
bucket = "terraform-state"
key = "staging/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
}
}Ein Lock über DynamoDB verhindert gleichzeitige Applies. Wenn bereits jemand den Produktions-State verändert, wartet das terraform apply des zweiten Entwicklers oder schlägt mit einem Lock-Fehler fehl – statt den State stillschweigend zu beschädigen.
Module-Versionierung
Gemeinsam genutzte module ohne Versionierung erzeugen eine gefährliche Kopplung: Aktualisiert man ein module für einen Service, kann das jeden anderen Service brechen, der dieses module verwendet.
# ❌ Referencing modules by local path — changes affect everyone immediately
module "ecs_service" {
source = "../../modules/ecs-service"
# If someone modifies this module, every consumer changes on next apply
}
# ✅ Versioned module references — consumers upgrade explicitly
module "ecs_service" {
source = "app.terraform.io/mycompany/ecs-service/aws"
version = "~> 2.1.0" # Accept 2.1.x patches, pin major.minor
service_name = "api"
container_port = 3000
desired_count = 3
}Wenn Teams ihre module in einer Registry veröffentlichen (Terraform Cloud, Artifactory oder auch nur Git-Tags), entscheiden die Konsumenten selbst, wann sie aktualisieren. Ein module-Update durchläuft seinen eigenen PR-, Test- und Release-Zyklus, bevor irgendeine Infrastruktur es tatsächlich nutzt.
Variablen-Hierarchie
Teams brauchen ein einheitliches Muster, um Variablen über mehrere Umgebungen hinweg zu verwalten, ohne die Konfiguration zu duplizieren.
# modules/ecs-service/variables.tf — module defines its interface
variable "service_name" {
description = "Name of the ECS service"
type = string
}
variable "desired_count" {
description = "Number of task replicas"
type = number
default = 2
}
variable "cpu" {
description = "CPU units for the task (1024 = 1 vCPU)"
type = number
default = 256
}
variable "memory" {
description = "Memory in MB for the task"
type = number
default = 512
}# environments/production/terraform.tfvars
desired_count = 5
cpu = 1024
memory = 2048
# environments/staging/terraform.tfvars
desired_count = 2
cpu = 256
memory = 512Jedes Umgebungsverzeichnis enthält seine eigene terraform.tfvars-Datei. Die Standardwerte von module dienen als sinnvolle Basis, die einzelne Umgebungen bei Bedarf überschreiben können.
Code-Review-Workflow
Jede Infrastrukturänderung sollte einen sichtbaren Plan erzeugen, den Reviewer vor dem Merge bewerten können.
# .github/workflows/terraform-pr.yml
name: Terraform Plan
on:
pull_request:
paths: ["infrastructure/**"]
jobs:
plan:
runs-on: ubuntu-latest
strategy:
matrix:
environment: [staging, production]
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Init
run: terraform init
working-directory: infrastructure/environments/${{ matrix.environment }}
- name: Validate
run: terraform validate
working-directory: infrastructure/environments/${{ matrix.environment }}
- name: Plan
id: plan
run: |
terraform plan -no-color -input=false \
-out=${{ matrix.environment }}.tfplan 2>&1 | tee plan_output.txt
working-directory: infrastructure/environments/${{ matrix.environment }}Die im PR geposteten Plan-Ausgaben zeigen genau, welche Ressourcen erstellt, geändert oder gelöscht werden. So erkennen Reviewer gefährliche Änderungen – etwa das Löschen einer Datenbank – bevor sie in die Produktion gelangen.
Namenskonventionen
Einheitliche Namensgebung beseitigt jede Unklarheit darüber, was von Terraform verwaltet wird und was manuell angelegt wurde.
# ❌ Arbitrary names — impossible to trace back to Terraform
resource "aws_security_group" "sg1" {
name = "my-sg"
}
# ✅ Structured naming with standard tags
locals {
name_prefix = "${var.project}-${var.environment}"
}
resource "aws_security_group" "api" {
name = "${local.name_prefix}-api-sg"
description = "Security group for API servers"
vpc_id = var.vpc_id
tags = {
Name = "${local.name_prefix}-api-sg"
Project = var.project
Environment = var.environment
ManagedBy = "terraform"
Module = "ecs-service"
}
}Das Tag ManagedBy = "terraform" zeigt in der Konsole auf einen Blick, welche Ressourcen über IaC verwaltet werden und welche manuell entstanden sind.
Bestehende Ressourcen importieren und übernehmen
Nur selten starten Teams auf der grünen Wiese. Bereits vorhandene, manuell erstellte Ressourcen müssen in die Verwaltung durch Terraform importiert werden, ohne sie neu anzulegen.
# Import an existing RDS instance into Terraform state
terraform import aws_db_instance.main myapp-production-db
# After import, write the matching configuration
# terraform plan should show no changes if config matches realityDie wichtigsten Punkte
- State pro Umgebung isolieren – getrennte State-Dateien mit DynamoDB-Lock verhindern Katastrophen durch gleichzeitige Änderungen
- Module versionieren – die Konsumenten sollten selbst bestimmen, wann sie module-Änderungen übernehmen
- Tfvars pro Umgebung verwenden – gleiche module, unterschiedliche Parameter, einheitliche Struktur
- Plan in der CI bei jedem PR – Infrastrukturänderungen sichtbar und überprüfbar machen, bevor sie angewendet werden
- Namensgebung und Tags standardisieren –
ManagedBy = "terraform"macht IaC-verwaltete Ressourcen sofort erkennbar - Vor dem Neuanlegen importieren – bestehende Ressourcen sicher in die Terraform-Verwaltung überführen


