DBAtlas · Atlas für Datenbankbetrieb

Datenbank-Provisioning mit Terraform (IaC)

Symptom

Ziel: Datenbankinfrastruktur (Instanz, Parametergruppe, Netzwerk) mit Terraform als Code definieren (Infrastructure as Code); den Ablauf aus plan/apply, Remote State und Drift-Management einrichten.

1. Provider wählen und konfigurieren (aws / google / azurerm)

Definiere den Provider für deine Cloud und fixiere seine Version. Lege im Block required_providers den Provider hashicorp/aws für AWS, hashicorp/google für GCP und hashicorp/azurerm für Azure fest. Das Fixieren der Version sorgt für einheitliches Verhalten im Team.

PostgreSQL

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "eu-central-1"
}

2. Remote State und Locking einrichten

Halte die State-Datei nicht lokal; nutze für Teamarbeit und Sicherheit ein Remote Backend. Üblich sind das S3-Backend + eine DynamoDB-Lock-Tabelle auf AWS, das gcs-Backend auf GCP und das azurerm-Backend (Storage Account) auf Azure. Remote State verhindert per Locking gleichzeitige Applies und macht den State zur einzigen Quelle der Wahrheit. Da Passwörter im Klartext im State stehen können, halte das Backend verschlüsselt und zugriffsbeschränkt.

PostgreSQL

terraform {
  backend "s3" {
    bucket         = "company-tfstate"
    key            = "db/terraform.tfstate"
    region         = "eu-central-1"
    dynamodb_table = "tf-lock"
    encrypt        = true
  }
}

3. Datenbankressource definieren

Schreibe die Hauptressource für deine Engine und Cloud: aws_db_instance auf AWS (bzw. aws_rds_cluster für Aurora), google_sql_database_instance auf GCP, azurerm_mssql_database auf Azure (für SQL Server unter einem azurerm_mssql_server). Gib hier Engine, Version, Klasse, Storage und Backup-Fenster an.

PostgreSQL

resource "aws_db_instance" "pg" {
  identifier        = "app-db"
  engine            = "postgres"
  engine_version    = "16"
  instance_class    = "db.t3.medium"
  allocated_storage = 50
  db_name           = "appdb"
  username          = "pgadmin"
  password          = var.db_password
  backup_retention_period = 7
}

SQL Server

resource "azurerm_mssql_database" "db" {
  name      = "appdb"
  server_id = azurerm_mssql_server.srv.id
  sku_name  = "S1"
}

4. Parametergruppe als Code schreiben

Definiere Datenbankeinstellungen (max_connections, work_mem, Zeichensatz) mit einer Parameterressource statt manuell in der Konsole. Verwende aws_db_parameter_group auf AWS, settings.database_flags innerhalb von google_sql_database_instance auf GCP und die Ressource für die Serverkonfiguration auf Azure. Die Einstellungen sind dann versioniert und reproduzierbar.

PostgreSQL

resource "aws_db_parameter_group" "pg" {
  name   = "app-pg16"
  family = "postgres16"

  parameter {
    name  = "max_connections"
    value = "200"
  }
}
# inside aws_db_instance:
# parameter_group_name = aws_db_parameter_group.pg.name

5. Secrets über Variablen und einen Secrets Manager übergeben

Schreibe das Passwort nicht fest in eine .tf-Datei; definiere es als sensible Variable (variable ... sensitive = true) und liefere den Wert über eine TF_VAR_-Umgebungsvariable, einen Secrets Manager (AWS Secrets Manager, Vault) oder ein CI-Secret. Beachte: Der Wert wird in die State-Datei geschrieben, daher muss der Remote State verschlüsselt sein. Am saubersten ist es, das Passwort gar nicht an Terraform zu übergeben und es stattdessen aus einer Secrets-Manager-Ressource zu lesen.

PostgreSQL

variable "db_password" {
  type      = string
  sensitive = true
}

# CI/shell:
export TF_VAR_db_password="$(vault kv get -field=pw secret/db)"

6. Den Ablauf aus plan und apply ausführen

Bereite zuerst mit terraform init Provider und Backend vor, sieh dir mit terraform plan an, was sich ändert, gib frei und wende mit terraform apply an. Wende nichts an, ohne die Plan-Ausgabe geprüft zu haben; der sichere Ablauf in CI ist, den 'plan' als PR-Kommentar zu posten und nach menschlicher Freigabe anzuwenden. Erkenne destruktive Änderungen (z. B. Neuanlage der Instanz) am Marker -/+ in der Plan-Ausgabe.

PostgreSQL

terraform init
terraform plan -out=plan.tfplan
terraform apply plan.tfplan

7. Drift erkennen und beheben

Nimmt jemand eine manuelle Änderung in der Konsole vor, weichen reale Infrastruktur und State voneinander ab (Drift). Unterschiede, die in terraform plan auftauchen, 'obwohl sich nichts hätte ändern sollen', decken Drift auf; die Differenz wird mit terraform refresh/plan ermittelt. Übernimm die Änderung entweder in den Code oder bringe die Infrastruktur per apply auf den Stand des Codes zurück. Verbiete manuelle Änderungen grundsätzlich; der Code sollte die einzige Quelle der Wahrheit sein.

PostgreSQL

# drift check (when no changes are expected):
terraform plan
# expect 'No changes'; any diff means drift
# bring an existing resource into state with import:
terraform import aws_db_instance.pg app-db
In DBAtlas öffnen →