Zum Hauptinhalt springen

Terraform

Definition

Terraform ist ein Open-Source-Infrastructure-as-Code-Werkzeug (IaC) von HashiCorp, das es ermöglicht, Cloud- und On-Premises-Infrastruktur mithilfe einer deklarativen Konfigurationssprache namens HCL (HashiCorp Configuration Language) zu definieren, bereitzustellen und zu verwalten. Man beschreibt den gewünschten Endzustand der Infrastruktur — welche Ressourcen existieren sollen, wie sie konfiguriert sein sollen und wie sie miteinander in Beziehung stehen — und Terraform ermittelt, was zu erstellen, zu aktualisieren oder zu löschen ist, um diesen Zustand zu erreichen. Dieses deklarative Modell unterscheidet sich grundlegend von imperativen Scripting-Ansätzen, bei denen man die Abfolge der auszuführenden Schritte beschreibt.

Das Herzstück von Terraforms Architektur ist sein Provider-Ökosystem. Ein Provider ist ein Plugin, das HCL-Ressourcendefinitionen in API-Aufrufe gegen eine bestimmte Plattform übersetzt: AWS, Google Cloud, Azure, Kubernetes, Datadog, GitHub und Hunderte mehr. Jeder Provider pflegt seinen eigenen versionierten Release-Zyklus, und Terraform lädt Provider automatisch basierend auf required_providers-Blöcken herunter. Das bedeutet, dass eine einzige Terraform-Konfiguration gleichzeitig ein AWS-GPU-Trainingscluster, einen GCS-Bucket für Trainingsdaten, einen Kubernetes-Namespace für Model-Serving und ein Grafana-Dashboard für Monitoring bereitstellen kann — mit konsistenten Werkzeugen über alle Plattformen hinweg.

State-Management macht Terraform idempotent und planbar. Terraform pflegt eine State-Datei, die jede Ressource in der Konfiguration ihrem realen Gegenstück zuordnet (identifiziert durch Cloud-Provider-Ressourcen-IDs). Wenn terraform plan ausgeführt wird, vergleicht Terraform die aktuelle State-Datei mit der Konfiguration und der lebenden Infrastruktur und erstellt ein Diff, das genau zeigt, was sich ändern wird, bevor eine Änderung vorgenommen wird. Für Team-Workflows wird der Zustand in einem gemeinsamen Backend (S3, GCS, Terraform Cloud) mit Sperren gespeichert, um gleichzeitige Änderungen zu verhindern. Diese Nachvollziehbarkeit und Vorhersagbarkeit machen Terraform zum dominanten IaC-Werkzeug für die Bereitstellung von ML-Training- und -Serving-Infrastruktur in regulierten und kollaborativen Umgebungen.

Funktionsweise

Konfiguration schreiben

Ingenieure schreiben HCL-Dateien (.tf), die Ressourcen, Datenquellen, Variablen, Ausgaben und Module deklarieren. Ressourcen entsprechen Infrastrukturobjekten (eine EC2-Instanz, ein S3-Bucket, ein Kubernetes-Deployment). Datenquellen lesen bestehende Infrastruktur, ohne sie zu verwalten. Variablen parametrisieren Konfigurationen für die Wiederverwendung in verschiedenen Umgebungen. Module kapseln wiederverwendbare Ressourcenmengen — ein „GPU-Trainingscluster"-Modul kann mehrfach mit unterschiedlichen Instanztypen und Regionen instanziiert werden.

Initialisieren und Planen

terraform init lädt erforderliche Provider und Module herunter und initialisiert das Backend. terraform plan erstellt einen menschenlesbaren Ausführungsplan: eine Liste von Ressourcen, die hinzugefügt (+), geändert (~) oder gelöscht (−) werden sollen. Die Plan-Phase ist schreibgeschützt — sie nimmt keine Änderungen an der Infrastruktur vor. Teams integrieren terraform plan typischerweise in CI-Pipelines, um Änderungen in Pull Requests vor dem Merge zu überprüfen.

Anwenden und State-Management

terraform apply führt den Plan aus und ruft Provider-APIs auf, um Ressourcen in Abhängigkeitsreihenfolge zu erstellen, zu aktualisieren oder zu löschen. Terraform löst den Abhängigkeitsgraph automatisch basierend auf Referenzen zwischen Ressourcen auf (z. B. ein Subnetz, das auf eine VPC-ID verweist). Nach dem Apply wird die State-Datei aktualisiert, um den neuen Infrastrukturzustand widerzuspiegeln. Für ML-Infrastruktur bedeutet das, dass GPU-Instanzen, Speicher-Buckets, IAM-Rollen und Kubernetes-Cluster alle in der richtigen Reihenfolge mit den richtigen Konfigurationen in einem einzigen Befehl erstellt werden.

Löschen und Lifecycle-Management

terraform destroy löscht alle von der Konfiguration verwalteten Ressourcen — nützlich für ephemere Trainingsumgebungen, die zwischen Trainingsjobs nicht laufen (und Geld kosten) sollen. Lifecycle-Meta-Argumente (create_before_destroy, prevent_destroy, ignore_changes) geben feingranulare Kontrolle darüber, wie Terraform mit sensiblen Ressourcen wie Modell-Artefakt-Speicher-Buckets umgeht, die niemals versehentlich gelöscht werden dürfen.

Wann verwenden / Wann NICHT verwenden

Verwenden wennVermeiden wenn
Cloud-Infrastruktur bereitgestellt werden soll, die über Umgebungen hinweg reproduzierbar sein mussSoftware in bestehenden Instanzen konfiguriert werden soll (dafür Ansible verwenden)
ML-Infrastruktur im großen Maßstab verwaltet wird: GPU-Cluster, Speicher, Netzwerk, KubernetesDas Team keine Cloud-Infrastruktur zu verwalten hat (keine Server, keine Cloud-Accounts)
Mehrere Teammitglieder an derselben Infrastruktur zusammenarbeiten müssenBeliebige Shell-Befehle ausgeführt oder OS-Einstellungen auf Instanzen konfiguriert werden müssen
Infrastrukturänderungen vor der Anwendung via Pull Requests überprüft werden sollenBestehende Infrastruktur nicht mit Terraform erstellt wurde und Migrationskosten zu hoch sind
Infrastruktur versioniert, auditiert und zuverlässig zurückgerollt werden mussSchnelle, iterative Änderungen an der Anwendungskonfiguration während der Entwicklung benötigt werden
In mehreren Cloud-Providern gearbeitet wird und ein einheitlicher Workflow gewünscht wirdDie Organisation bereits auf ein konkurrierendes IaC-Werkzeug (Pulumi, CDK) mit institutionellem Wissen standardisiert ist

Vergleiche

KriteriumTerraformAnsible
ParadigmaDeklarativ — gewünschten Zustand beschreibenProzedural — Schritte zum Erreichen des Zustands beschreiben
State-ManagementExplizite State-Datei; verfolgt Ressourcen-IDsZustandslos — keine integrierte Zustandsverfolgung
Primärer AnwendungsfallCloud-Ressourcen-Bereitstellung (Instanzen, Netzwerke, Speicher)Konfigurationsmanagement und Anwendungsdeployment auf bestehenden Instanzen
Cloud-Anbieter-Unterstützung1.000+ Provider via Plugin-ÖkosystemModule für große Clouds; weniger umfassend als Terraform
IdempotenzNativ — Plan/Apply konvergiert immer zum gewünschten ZustandAufgabenebene — jede Aufgabe muss idempotent geschrieben sein
LernkurveHCL-Syntax + State/Plan-KonzeptYAML-Playbooks; niedrigere anfängliche Hürde
Gemeinsamer EinsatzTerraform stellt Infrastruktur bereit; Ansible konfiguriert Software darauf — sie ergänzen sichSiehe oben

Vor- und Nachteile

AspektVorteileNachteile
Deklaratives ModellAbsicht ist klar; Plan zeigt exakte Änderungen vor dem ApplyBedingte Logik oder komplexe Schleifen lassen sich schwer ausdrücken (obwohl HCL sich verbessert hat)
State-DateiErmöglicht genaue Planung und Drift-ErkennungState-Datei ist sensibel; Beschädigung oder Verlust ist ein ernster Vorfall
Provider-ÖkosystemDeckt praktisch jeden Cloud-Dienst und jedes SaaS-Tool abProvider-Qualität variiert; einige Community-Provider sind schlecht gepflegt
Plan/Apply-WorkflowÄnderungen sind vor der Ausführung überprüfbarLangsamerer Iterationszyklus als imperative Skripte für schnelles Prototyping
Modul-WiederverwendungDRY-Infrastrukturmuster via veröffentlichten oder internen ModulenGroße Modulgraphen können bei der Initialisierung und Planung langsam sein
IdempotenzSicher mehrfach ausführbar; konvergentes VerhaltenDestroy/Recreate-Zyklen bei bestimmten Ressourcenänderungen (z. B. Umbenennung) verursachen Ausfallzeiten

Code-Beispiele

# ml_infrastructure.tf
# Provisions an AWS GPU training instance and S3 bucket for ML artifacts.
# Prerequisites: AWS CLI configured, Terraform >= 1.5, appropriate IAM permissions.
# Run: terraform init && terraform plan && terraform apply

terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
# Remote state backend — replace with your bucket and key
backend "s3" {
bucket = "my-org-terraform-state"
key = "mlops/training/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-state-lock"
encrypt = true
}
}

provider "aws" {
region = var.aws_region
}

# --- Variables ---

variable "aws_region" {
description = "AWS region for all resources"
type = string
default = "us-east-1"
}

variable "environment" {
description = "Deployment environment: dev, staging, prod"
type = string
default = "dev"
}

variable "gpu_instance_type" {
description = "EC2 instance type for GPU training. p3.2xlarge has 1x V100."
type = string
default = "p3.2xlarge"
}

variable "key_pair_name" {
description = "Name of an existing EC2 key pair for SSH access"
type = string
}

# --- Data sources ---

# Use the latest Deep Learning AMI (GPU) for the region
data "aws_ami" "dl_ami" {
most_recent = true
owners = ["amazon"]

filter {
name = "name"
values = ["Deep Learning AMI GPU PyTorch*"]
}

filter {
name = "architecture"
values = ["x86_64"]
}
}

# Default VPC for simplicity — use a dedicated VPC in production
data "aws_vpc" "default" {
default = true
}

# --- S3 bucket for training artifacts ---

resource "aws_s3_bucket" "ml_artifacts" {
bucket = "ml-artifacts-${var.environment}-${random_id.suffix.hex}"

tags = {
Environment = var.environment
Purpose = "ml-training-artifacts"
ManagedBy = "terraform"
}
}

resource "random_id" "suffix" {
byte_length = 4
}

# Block all public access to the artifacts bucket
resource "aws_s3_bucket_public_access_block" "ml_artifacts" {
bucket = aws_s3_bucket.ml_artifacts.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

# Enable versioning so artifact overwrites can be recovered
resource "aws_s3_bucket_versioning" "ml_artifacts" {
bucket = aws_s3_bucket.ml_artifacts.id
versioning_configuration {
status = "Enabled"
}
}

# --- IAM role for the training instance ---

resource "aws_iam_role" "ml_training" {
name = "ml-training-role-${var.environment}"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = { Service = "ec2.amazonaws.com" }
}]
})

tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}

resource "aws_iam_role_policy" "ml_s3_access" {
name = "ml-s3-access"
role = aws_iam_role.ml_training.id

policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket",
"s3:DeleteObject"
]
Resource = [
aws_s3_bucket.ml_artifacts.arn,
"${aws_s3_bucket.ml_artifacts.arn}/*"
]
}]
})
}

resource "aws_iam_instance_profile" "ml_training" {
name = "ml-training-profile-${var.environment}"
role = aws_iam_role.ml_training.name
}

# --- Security group for training instance ---

resource "aws_security_group" "ml_training" {
name = "ml-training-sg-${var.environment}"
description = "Security group for ML GPU training instances"
vpc_id = data.aws_vpc.default.id

# SSH access — restrict to your IP in production
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "SSH — restrict to known IPs in production"
}

# JupyterLab access
ingress {
from_port = 8888
to_port = 8888
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "JupyterLab — restrict to known IPs in production"
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound traffic"
}

tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}

# --- GPU Training EC2 instance ---

resource "aws_instance" "ml_training" {
ami = data.aws_ami.dl_ami.id
instance_type = var.gpu_instance_type
key_name = var.key_pair_name
iam_instance_profile = aws_iam_instance_profile.ml_training.name
vpc_security_group_ids = [aws_security_group.ml_training.id]

# 100 GB root volume for datasets and model checkpoints
root_block_device {
volume_type = "gp3"
volume_size = 100
delete_on_termination = true
encrypted = true
}

# Bootstrap script: export the S3 bucket name as an environment variable
user_data = <<-EOF
#!/bin/bash
echo "export ML_ARTIFACTS_BUCKET=${aws_s3_bucket.ml_artifacts.bucket}" >> /etc/environment
echo "export AWS_DEFAULT_REGION=${var.aws_region}" >> /etc/environment
EOF

tags = {
Name = "ml-training-${var.environment}"
Environment = var.environment
Purpose = "gpu-training"
ManagedBy = "terraform"
}

# Prevent accidental destruction in production
lifecycle {
prevent_destroy = false # Set to true for production instances
}
}

# --- Outputs ---

output "training_instance_id" {
description = "EC2 instance ID of the GPU training instance"
value = aws_instance.ml_training.id
}

output "training_instance_public_ip" {
description = "Public IP address of the GPU training instance"
value = aws_instance.ml_training.public_ip
}

output "ml_artifacts_bucket_name" {
description = "Name of the S3 bucket for ML artifacts"
value = aws_s3_bucket.ml_artifacts.bucket
}

output "ml_artifacts_bucket_arn" {
description = "ARN of the S3 bucket for ML artifacts"
value = aws_s3_bucket.ml_artifacts.arn
}

Praktische Ressourcen

Siehe auch