531 lines
12 KiB
Markdown
Executable File
531 lines
12 KiB
Markdown
Executable File
#infrastructure #Cloud
|
||
## 1. Was ist Terraform?
|
||
|
||
Terraform ist ein Open-Source-Tool (ursprünglich MIT, seit 2023 Business Source License, BSL) von HashiCorp zur **deklarativen** Beschreibung und Verwaltung von Infrastruktur als Code (Infrastructure as Code, IaC).
|
||
|
||
Mit Terraform kannst du:
|
||
|
||
- Infrastruktur in Cloud-Providern (AWS, Azure, GCP, …), On-Premise und weiteren Systemen **beschreiben** (als Code).
|
||
- Aus dieser Beschreibung eine **gewünschte Zielkonfiguration** (Desired State) definieren.
|
||
- Terraform berechnet dann, **welche Änderungen nötig sind**, um vom Ist-Zustand zum Soll-Zustand zu gelangen.
|
||
- Diese Änderungen werden mit `terraform apply` **automatisch ausgeführt**.
|
||
|
||
Terraform ist besonders stark in:
|
||
|
||
- **Multi-Cloud- und Hybrid-Szenarien**
|
||
- **Reproduzierbaren Umgebungen** (z.B. Dev, Test, Prod)
|
||
- **Versionierbarer Infrastruktur** (Git)
|
||
- **Team-Kollaboration** an Infrastruktur
|
||
|
||
---
|
||
|
||
## 2. Grundkonzepte von Terraform
|
||
|
||
Die wichtigsten Bausteine:
|
||
|
||
### 2.1 Provider
|
||
|
||
Provider sind die „Treiber“, mit denen Terraform mit einem externen System spricht, z.B.:
|
||
|
||
- `aws` – Amazon Web Services
|
||
- `azurerm` – Microsoft Azure
|
||
- `google` – Google Cloud
|
||
- `kubernetes` – Kubernetes-Cluster
|
||
- `helm`, `docker`, `vault`, `github`, viele weitere
|
||
|
||
In Terraform-Code bindet man einen Provider ein, z.B.:
|
||
|
||
```hcl
|
||
terraform {
|
||
required_providers {
|
||
aws = {
|
||
source = "hashicorp/aws"
|
||
version = "~> 5.0"
|
||
}
|
||
}
|
||
}
|
||
|
||
provider "aws" {
|
||
region = "eu-central-1"
|
||
}
|
||
```
|
||
|
||
### 2.2 Ressourcen
|
||
|
||
**Ressourcen** (`resource`) sind die eigentlichen Infrastruktur-Objekte, z.B.:
|
||
|
||
- `aws_instance` (EC2-VM)
|
||
- `aws_s3_bucket`
|
||
- `azurerm_resource_group`
|
||
- `google_compute_instance`
|
||
|
||
Beispiel:
|
||
|
||
```hcl
|
||
resource "aws_s3_bucket" "example" {
|
||
bucket = "mein-terraform-bucket-12345"
|
||
acl = "private"
|
||
}
|
||
```
|
||
|
||
`aws_s3_bucket` ist der Ressourcentyp, `"example"` der Name innerhalb der Terraform-Konfiguration.
|
||
|
||
### 2.3 Datenquellen (Data Sources)
|
||
|
||
`data`-Blöcke lesen Informationen aus einer bestehenden Umgebung, ohne etwas zu verändern.
|
||
|
||
```hcl
|
||
data "aws_ami" "ubuntu" {
|
||
most_recent = true
|
||
|
||
filter {
|
||
name = "name"
|
||
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
|
||
}
|
||
|
||
owners = ["099720109477"] # Canonical
|
||
}
|
||
```
|
||
|
||
Die Daten können dann in Ressourcen verwendet werden.
|
||
|
||
### 2.4 Variablen und Outputs
|
||
|
||
**Variablen** (`variable`) erlauben Parametrisierung:
|
||
|
||
```hcl
|
||
variable "region" {
|
||
type = string
|
||
default = "eu-central-1"
|
||
description = "AWS Region"
|
||
}
|
||
```
|
||
|
||
Aufgerufen z.B.: `var.region`.
|
||
|
||
**Outputs** (`output`) geben wichtige Informationen aus (z.B. IP-Adressen):
|
||
|
||
```hcl
|
||
output "instance_ip" {
|
||
value = aws_instance.web.public_ip
|
||
}
|
||
```
|
||
|
||
### 2.5 Module
|
||
|
||
Module sind wiederverwendbare Bausteine von Terraform-Konfigurationen (eine Art „Bibliothek“ von Infrastruktur).
|
||
|
||
- Ein Modul ist einfach ein Ordner mit `.tf`-Dateien.
|
||
- Man kann eigene Module oder Community-Module nutzen (z.B. aus dem Terraform Registry).
|
||
|
||
Beispiel Nutzung eines Moduls:
|
||
|
||
```hcl
|
||
module "network" {
|
||
source = "./modules/network"
|
||
|
||
vpc_cidr = "10.0.0.0/16"
|
||
}
|
||
```
|
||
|
||
Oder:
|
||
|
||
```hcl
|
||
module "vpc" {
|
||
source = "terraform-aws-modules/vpc/aws"
|
||
version = "5.0.0"
|
||
|
||
name = "main-vpc"
|
||
cidr = "10.0.0.0/16"
|
||
azs = ["eu-central-1a", "eu-central-1b"]
|
||
}
|
||
```
|
||
|
||
### 2.6 Terraform State
|
||
|
||
Terraform hält den Zustand der verwalteten Ressourcen in einer **State-Datei** (`terraform.tfstate`) fest.
|
||
|
||
- Der State ist die „Wahrheit“, mit der Terraform den Ist-Zustand kennt.
|
||
- Daran erkennt Terraform, welche Ressource es schon erstellt hat und wie deren IDs, Attribute usw. sind.
|
||
- Änderungen am Code werden mit dem State abgeglichen → Terraform generiert einen Plan.
|
||
|
||
State kann liegen:
|
||
|
||
- lokal: `terraform.tfstate` im Projektordner
|
||
- remote (empfohlen für Teams): z.B. in S3, Azure Storage, GCS, Terraform Cloud, etc.
|
||
|
||
Beispiel Backend-Konfiguration (Remote State mit S3):
|
||
|
||
```hcl
|
||
terraform {
|
||
backend "s3" {
|
||
bucket = "my-terraform-state-bucket"
|
||
key = "prod/terraform.tfstate"
|
||
region = "eu-central-1"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Typischer Terraform-Workflow
|
||
|
||
### 3.1 Projektstruktur
|
||
|
||
Beispiel:
|
||
|
||
```text
|
||
.
|
||
├── main.tf # Ressourcen, Module
|
||
├── variables.tf # Variablen
|
||
├── outputs.tf # Outputs
|
||
└── providers.tf # Provider / Backend
|
||
```
|
||
|
||
### 3.2 Wichtige Terraform-Kommandos
|
||
|
||
1. `terraform init`
|
||
- Initialisiert das Projekt
|
||
- Lädt Provider-Plugins
|
||
- Konfiguriert Backend (State)
|
||
|
||
2. `terraform plan`
|
||
- Zeigt, was Terraform ändern würde (Create/Update/Delete)
|
||
- Verändert noch nichts
|
||
- Wichtig für Review (z.B. im CI)
|
||
|
||
3. `terraform apply`
|
||
- Führt den Plan aus (Standard: vorher Anzeige + Bestätigung)
|
||
- Erzeugt/aktualisiert/löscht Ressourcen
|
||
|
||
4. `terraform destroy`
|
||
- Löscht alle Ressourcen, die Terraform verwaltet
|
||
- Vorsicht: de facto „Infrastruktur-Abbau“
|
||
|
||
Typischer Ablauf:
|
||
|
||
```bash
|
||
terraform init
|
||
terraform plan
|
||
terraform apply
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Terraform-Sprache: HCL (HashiCorp Configuration Language)
|
||
|
||
Terraform benutzt HCL, eine deklarative, blockbasierte Sprache.
|
||
|
||
### 4.1 Syntax-Grundlagen
|
||
|
||
Blöcke haben Form:
|
||
|
||
```hcl
|
||
resource "TYP" "NAME" {
|
||
argument = "value"
|
||
|
||
block {
|
||
nested_arg = 123
|
||
}
|
||
}
|
||
```
|
||
|
||
Datentypen:
|
||
|
||
- `string` – `"Text"`
|
||
- `number` – `42`
|
||
- `bool` – `true` / `false`
|
||
- Listen – `["a", "b"]`
|
||
- Maps – `{ key = "value" }`
|
||
- Objekte/Tuples – komplexere Typen
|
||
|
||
### 4.2 Expressions & Referenzen
|
||
|
||
Referenzen auf andere Ressourcen:
|
||
|
||
```hcl
|
||
resource "aws_instance" "web" {
|
||
ami = data.aws_ami.ubuntu.id
|
||
instance_type = var.instance_type
|
||
|
||
tags = {
|
||
Name = "web-${var.environment}"
|
||
}
|
||
}
|
||
```
|
||
|
||
Referenz-Regel:
|
||
|
||
- `ressourcentyp.name.attribut`
|
||
- z.B. `aws_instance.web.public_ip`
|
||
|
||
---
|
||
|
||
## 5. Praktisches Beispiel
|
||
|
||
Ein minimaler Stack in AWS:
|
||
|
||
### `providers.tf`
|
||
|
||
```hcl
|
||
terraform {
|
||
required_version = ">= 1.6.0"
|
||
|
||
required_providers {
|
||
aws = {
|
||
source = "hashicorp/aws"
|
||
version = "~> 5.0"
|
||
}
|
||
}
|
||
}
|
||
|
||
provider "aws" {
|
||
region = var.region
|
||
}
|
||
```
|
||
|
||
### `variables.tf`
|
||
|
||
```hcl
|
||
variable "region" {
|
||
type = string
|
||
default = "eu-central-1"
|
||
description = "AWS Region"
|
||
}
|
||
|
||
variable "instance_type" {
|
||
type = string
|
||
default = "t3.micro"
|
||
}
|
||
|
||
variable "environment" {
|
||
type = string
|
||
default = "dev"
|
||
}
|
||
```
|
||
|
||
### `main.tf`
|
||
|
||
```hcl
|
||
data "aws_ami" "ubuntu" {
|
||
most_recent = true
|
||
|
||
filter {
|
||
name = "name"
|
||
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
|
||
}
|
||
|
||
owners = ["099720109477"]
|
||
}
|
||
|
||
resource "aws_instance" "web" {
|
||
ami = data.aws_ami.ubuntu.id
|
||
instance_type = var.instance_type
|
||
|
||
tags = {
|
||
Name = "web-${var.environment}"
|
||
Environment = var.environment
|
||
}
|
||
}
|
||
```
|
||
|
||
### `outputs.tf`
|
||
|
||
```hcl
|
||
output "web_instance_id" {
|
||
value = aws_instance.web.id
|
||
}
|
||
|
||
output "web_instance_ami" {
|
||
value = aws_instance.web.ami
|
||
}
|
||
```
|
||
|
||
Ablauf:
|
||
|
||
```bash
|
||
terraform init
|
||
terraform plan
|
||
terraform apply
|
||
```
|
||
|
||
---
|
||
|
||
## 6. Workspaces, Environments und Modularisierung
|
||
|
||
### 6.1 Workspaces
|
||
|
||
Terraform Workspaces ermöglichen getrennte States innerhalb desselben Codes (z.B. `default`, `dev`, `prod`).
|
||
|
||
```bash
|
||
terraform workspace list
|
||
terraform workspace new dev
|
||
terraform workspace select dev
|
||
```
|
||
|
||
Dann z.B.:
|
||
|
||
```hcl
|
||
variable "environment" {
|
||
default = terraform.workspace
|
||
}
|
||
```
|
||
|
||
Viele Teams gehen aber eher über **separate State-Dateien / Ordner / Repos** (z.B. `envs/dev`, `envs/prod`), statt Workspaces intensiv zu nutzen.
|
||
|
||
### 6.2 Module für Wiederverwendung
|
||
|
||
Struktur-Beispiel:
|
||
|
||
```text
|
||
.
|
||
├── main.tf
|
||
├── modules
|
||
│ ├── network
|
||
│ │ ├── main.tf
|
||
│ │ ├── variables.tf
|
||
│ │ └── outputs.tf
|
||
│ └── compute
|
||
│ ├── main.tf
|
||
│ ├── variables.tf
|
||
│ └── outputs.tf
|
||
```
|
||
|
||
In `main.tf`:
|
||
|
||
```hcl
|
||
module "network" {
|
||
source = "./modules/network"
|
||
vpc_cidr = "10.0.0.0/16"
|
||
}
|
||
|
||
module "compute" {
|
||
source = "./modules/compute"
|
||
vpc_id = module.network.vpc_id
|
||
subnets = module.network.subnet_ids
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Terraform Cloud / Terraform Enterprise
|
||
|
||
Neben der CLI gibt es:
|
||
|
||
- **Terraform Cloud** (SaaS von HashiCorp)
|
||
- **Terraform Enterprise** (Self-hosted)
|
||
|
||
Features:
|
||
|
||
- Remote-State-Storage
|
||
- Remote-Execution (Plans/Applies)
|
||
- Policies (Sentinel)
|
||
- Team & Governance (RBAC)
|
||
- UI für Runs, Logs, States, Variablen
|
||
|
||
Für kleine Teams reicht oft: Git + Remote State (S3/Azure/GCS) + CI/CD Pipeline.
|
||
|
||
---
|
||
|
||
## 8. Typische Anwendungsfälle
|
||
|
||
- **Cloud-Infrastruktur**:
|
||
- VPCs/Netzwerke, Subnets, Security Groups
|
||
- Compute (VMs, Managed Kubernetes, Serverless)
|
||
- Datenbanken, Caches, Messaging
|
||
- **Kubernetes-Infrastruktur**:
|
||
- Cluster (EKS/AKS/GKE)
|
||
- Add-ons via `kubernetes`-Provider, `helm`-Provider
|
||
- **Multi-Cloud-Szenarien**:
|
||
- Einheitliches Tool für AWS + Azure + GCP
|
||
- **On-Prem / Sonstiges**:
|
||
- VMware, OpenStack, F5, GitHub-Repos, DNS (Cloudflare/Route53), Monitoring (Datadog, New Relic), etc.
|
||
|
||
---
|
||
|
||
## 9. Vergleich zu anderen Tools
|
||
|
||
### Terraform vs. CloudFormation / ARM / Bicep
|
||
|
||
- Terraform:
|
||
- Provider-übergreifend (nicht auf eine Cloud beschränkt)
|
||
- HCL, verständliche Syntax
|
||
- CloudFormation (AWS) / ARM/Bicep (Azure) / Deployment Manager (GCP):
|
||
- Cloud-spezifisch, tief integriert
|
||
- Gut für reines Single-Cloud-Setup
|
||
- Multi-Cloud wird komplex
|
||
|
||
### Terraform vs. Ansible / Chef / Puppet
|
||
|
||
- Terraform:
|
||
- Fokus: **Provisioning** + Lebenszyklus von Ressourcen
|
||
- Deklarativ, fokus auf Infrastruktur
|
||
- Ansible/Chef/Puppet:
|
||
- Fokus: **Konfiguration** von Servern / Software
|
||
- IdR. auf bereits existierende Maschinen
|
||
|
||
Häufig werden Terraform + Ansible kombiniert:
|
||
Terraform baut VMs / Netzwerke, Ansible konfiguriert Software im OS.
|
||
|
||
### Terraform vs. Pulumi
|
||
|
||
- Pulumi: IaC mit **allgemeinen Programmiersprachen** (TypeScript, Python, Go, C#)
|
||
- Terraform: HCL, deklarativ, stark verbreitete Community
|
||
- Pulumi bietet mehr „Programmier-Features“ (Loops, Ifs) direkt in Sprache; Terraform hat ähnliche Mechanismen, aber bewusst begrenzt, um die Konfiguration simpel zu halten.
|
||
|
||
---
|
||
|
||
## 10. Best Practices & Stolperfallen
|
||
|
||
### 10.1 Best Practices
|
||
|
||
- **State nicht lokal** speichern, sondern Remote (z.B. S3 + DynamoDB Locking, Azure Storage + Locks).
|
||
- **State schützen**:
|
||
- Zugriff beschränken (IAM/RBAC)
|
||
- Backups
|
||
- **Struktur / Modularisierung**:
|
||
- Wiederverwendbare Module
|
||
- Trennung von Environments (dev/stage/prod)
|
||
- **Git-Workflow**:
|
||
- Terraform-Code in Repos
|
||
- PRs/Merge-Requests
|
||
- `terraform plan` via CI im PR anzeigen
|
||
- **Versionen pinnen**:
|
||
- Terraform-Version `required_version`
|
||
- Provider-Versionen fixieren (z.B. `~> 5.0`)
|
||
- **Kleine, inkrementelle Änderungen**:
|
||
- Große Umbauten in mehreren Schritten
|
||
- Plan gut reviewen
|
||
|
||
### 10.2 Typische Probleme
|
||
|
||
- **State-Drift**:
|
||
- Ressourcen werden außerhalb von Terraform geändert (z.B. in der Cloud-Konsole)
|
||
- Plan zeigt unerwartete Änderungen
|
||
- Lösung: soweit möglich alle Änderungen via Terraform; bei Drift bewusst entscheiden (import, adopt, ignore)
|
||
- **Manuelles Löschen von Ressourcen**:
|
||
- Terraform „denkt“, Ressource existiert noch
|
||
- Beim nächsten Apply werden sie ggf. neu erstellt
|
||
- **Zyklen in Abhängigkeiten**:
|
||
- Falsche Referenzen können zyklische Abhängigkeiten erzeugen
|
||
- **Große States**:
|
||
- Sehr viele Ressourcen in einem State → langsamere Plans, unübersichtliche Fehler
|
||
- Lösung: Aufteilen in mehrere Terraform-Projekte / States (z.B. pro Domäne/Layer)
|
||
|
||
---
|
||
|
||
## 11. Aktuelle Entwicklungen: Lizenz & OpenTofu
|
||
|
||
HashiCorp hat 2023 die Lizenz von Terraform auf die **Business Source License (BSL)** geändert.
|
||
Daraufhin entstand ein **Community-Fork**:
|
||
|
||
- **OpenTofu** (ehemals OpenTF):
|
||
- Komplett Open Source (MPL 2.0)
|
||
- CLI & HCL weitgehend kompatibel zu Terraform (Stand heute)
|
||
- Ziel: drop-in Replacement für viele Terraform-Usecases
|
||
|
||
Für einen Einstieg in IaC ist es aber sinnvoll, zuerst die Konzepte anhand von Terraform zu verstehen – die meisten davon sind für OpenTofu nahezu identisch.
|
||
|
||
---
|
||
|