Zum Hauptinhalt springen
S-EDV news
← Alle Anleitungen
📘 Anleitung Datenbanken 03.08.2026 · 10 min Lesezeit

Temporal mit Docker installieren: Durable-Execution-Plattform für fehlertolerante Workflow-Orchestrierung

Temporal persistiert jeden Workflow-Schritt in PostgreSQL – kein Job geht verloren, auch nach Absturz oder Neustart. Diese Anleitung zeigt das aktuelle Docker-Compose-Setup mit temporalio/server 1.31.0 und PostgreSQL 16.

Temporal mit Docker installieren. Moderne IT Illustration einer Durable Execution Plattform mit Docker Containern, Workflow Orchestrierung, automatischen Retries, persistenter Speicherung, Observability und Server Infrastruktur für fehlertolerante Microse KI-generiert

Kein Job darf verloren gehen – das ist die Kernaussage hinter Temporal, einer Open-Source-Plattform für Durable Execution. Der gesamte Workflow-Zustand wird nach jedem Schritt in einer Datenbank persistiert; bricht ein Worker-Prozess ab, läuft der Workflow genau dort weiter, wo er aufgehört hat – ganz ohne Boilerplate-Fehlerbehandlung im eigenen Code. Temporal eignet sich für verteilte Transaktionen nach dem Saga-Pattern, langlaufende Prozesse (Minuten bis Monate), Zahlungsabwicklung, Onboarding-Flows und KI-Agenten-Orchestrierung. Mit über 20.000 GitHub-Stars und mehr als 900.000 wöchentlichen Docker-Pulls ist es die meistgenutzte Open-Source-Workflow-Engine für Microservices. Diese Anleitung richtet sich an Entwickler und Administratoren, die Temporal auf einem beliebigen Linux-Host (Ubuntu/Debian, VM, NAS mit Docker) lokal oder auf einem kleinen Produktivserver betreiben möchten.

Voraussetzungen

  1. Docker Engine >= 24.x und das Docker Compose Plugin >= 2.x müssen installiert sein. Prüfe mit docker compose version. Eine vollständige Installationsanleitung findest du in Docker und Docker Compose auf Linux installieren.
  2. git für das Klonen des offiziellen samples-server-Repositories (Skripte und dynamische Konfiguration werden zwingend benötigt).
  3. Mindestens 4 GB freier RAM (Temporal-Server + PostgreSQL + UI; mit Elasticsearch: 8 GB empfohlen).
  4. Mindestens 10 GB freier Festplattenplatz für Images und das PostgreSQL-Daten-Volume (~120 MB Images für die PostgreSQL-only-Variante).
  5. Internet-Zugang für den initialen Image-Download.
  6. Optionaler Browser (Chrome/Firefox) für die Web-UI auf localhost:8080.
  7. Sicherheitshinweis: Temporal-Dienste dürfen niemals direkt im Internet erreichbar sein – behandle sie wie eine Datenbank und betreibe sie ausschließlich in vertrauenswürdigen internen Netzwerken oder hinter einem Reverse Proxy mit Authentifizierung. Für HTTPS-Termination eignet sich z. B. Traefik als Docker-Reverse-Proxy.

Eckdaten auf einen Blick

EigenschaftWert
Temporal-Server-Imagetemporalio/server:1.31.0
Admin-Tools-Imagetemporalio/admin-tools:1.31.0
Web-UI-Imagetemporalio/ui:2.49.1
Datenbank-Imagepostgres:16
gRPC-Port (Pflicht)7233
Web-UI-Port8080
PostgreSQL-Port5432 (intern; optional nach außen)
RAM-Bedarfmind. 4 GB
Installationszeitca. 20 Minuten
LizenzMIT (Open Source)
Volume / MountZweck
postgres_dataAlle Workflow-Historien und -Zustände in PostgreSQL (Named Volume, Pflicht für Persistenz)
./dynamicconfigEnthält development-sql.yaml für Rate-Limits und Feature-Flags (Pflicht, muss vor Start existieren)
./scriptsShell-Skripte für Schema-Setup und Namespace-Anlegen (aus samples-server-Repository)

Schritt 1: Repository klonen und Projektordner vorbereiten

Das offizielle temporalio/docker-compose-Repository ist archiviert. Die aktuellen Compose-Dateien und die zwingend benötigten Shell-Skripte liegen im samples-server-Repository. Klone es und wechsle in das richtige Unterverzeichnis:

git clone https://github.com/temporalio/samples-server.git
cd samples-server/compose

Im Verzeichnis compose/ findest du bereits fertige Compose-Varianten. Für die PostgreSQL-only-Installation (ohne Elasticsearch) arbeitest du wahlweise mit der vorhandenen docker-compose-postgres.yml als Referenz oder legst – wie im nächsten Schritt gezeigt – eine eigene compose.yaml im selben Verzeichnis an. Wichtig: Das Unterverzeichnis scripts/ und dynamicconfig/ müssen relativ zum Compose-Verzeichnis vorhanden sein. Prüfe das kurz:

ls scripts/ dynamicconfig/

Beide Verzeichnisse sollten existieren und die Dateien setup-postgres.sh, create-namespace.sh sowie dynamicconfig/development-sql.yaml enthalten.

Verifizieren: Der Befehl ls scripts/setup-postgres.sh scripts/create-namespace.sh dynamicconfig/development-sql.yaml muss alle drei Dateien ohne Fehler ausgeben. Fehlt eine Datei, bitte nochmals prüfen, ob du im richtigen Verzeichnis (samples-server/compose) bist.

Schritt 2: .env-Datei mit gepinnten Versionen anlegen

Erstelle eine .env-Datei im Compose-Verzeichnis. Immer konkrete Image-Tags pinnen – niemals :latest verwenden, da Datenbankschema-Änderungen zwischen Versionen zu Inkompatibilitäten führen können. Wichtig: TEMPORAL_VERSION und TEMPORAL_ADMINTOOLS_VERSION müssen identisch sein.

# Temporal Docker Compose – Versionspinning
POSTGRESQL_VERSION=16
TEMPORAL_VERSION=1.31.0
TEMPORAL_ADMINTOOLS_VERSION=1.31.0
TEMPORAL_UI_VERSION=2.49.1

# Datenbank-Zugangsdaten (in Produktion starke Passwörter setzen!)
POSTGRES_USER=temporal
POSTGRES_PASSWORD=temporal

Verifizieren: cat .env zeigt alle sechs Variablen. Achte darauf, dass keine Leerzeichen um das =-Zeichen stehen.

Schritt 3: compose.yaml anlegen

Lege die folgende compose.yaml im Compose-Verzeichnis an. Der Stack startet fünf Dienste in definierter Reihenfolge: PostgreSQL wird zuerst hochgefahren und per Healthcheck geprüft; erst dann führt temporal-admin-tools das Schema-Setup durch; nach dessen Abschluss startet temporal; sobald er gesund ist, wird der Namespace angelegt und die UI gestartet.

services:
  postgresql:
    image: postgres:${POSTGRESQL_VERSION:-16}
    container_name: temporal-postgresql
    restart: unless-stopped
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-temporal}
      POSTGRES_USER: ${POSTGRES_USER:-temporal}
    networks:
      - temporal-network
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U temporal"]
      interval: 5s
      timeout: 5s
      retries: 60
      start_period: 30s

  temporal-admin-tools:
    image: temporalio/admin-tools:${TEMPORAL_ADMINTOOLS_VERSION:-1.31.0}
    container_name: temporal-admin-tools
    restart: on-failure:6
    depends_on:
      postgresql:
        condition: service_healthy
    environment:
      - DB=postgres12
      - DB_PORT=5432
      - POSTGRES_USER=${POSTGRES_USER:-temporal}
      - POSTGRES_PWD=${POSTGRES_PASSWORD:-temporal}
      - POSTGRES_SEEDS=postgresql
      - SQL_PASSWORD=${POSTGRES_PASSWORD:-temporal}
    networks:
      - temporal-network
    volumes:
      - ./scripts:/scripts
    entrypoint: ["/bin/sh"]
    command: /scripts/setup-postgres.sh

  temporal:
    image: temporalio/server:${TEMPORAL_VERSION:-1.31.0}
    container_name: temporal
    restart: unless-stopped
    depends_on:
      temporal-admin-tools:
        condition: service_completed_successfully
    environment:
      - DB=postgres12
      - DB_PORT=5432
      - POSTGRES_USER=${POSTGRES_USER:-temporal}
      - POSTGRES_PWD=${POSTGRES_PASSWORD:-temporal}
      - POSTGRES_SEEDS=postgresql
      - BIND_ON_IP=0.0.0.0
      - DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development-sql.yaml
    networks:
      - temporal-network
    ports:
      - "7233:7233"
    volumes:
      - ./dynamicconfig:/etc/temporal/config/dynamicconfig
    healthcheck:
      test: ["CMD", "nc", "-z", "localhost", "7233"]
      interval: 5s
      timeout: 3s
      start_period: 30s
      retries: 60

  temporal-create-namespace:
    image: temporalio/admin-tools:${TEMPORAL_ADMINTOOLS_VERSION:-1.31.0}
    container_name: temporal-create-namespace
    restart: on-failure:5
    depends_on:
      temporal:
        condition: service_healthy
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
      - DEFAULT_NAMESPACE=default
    networks:
      - temporal-network
    volumes:
      - ./scripts:/scripts
    entrypoint: ["/bin/sh"]
    command: /scripts/create-namespace.sh

  temporal-ui:
    image: temporalio/ui:${TEMPORAL_UI_VERSION:-2.49.1}
    container_name: temporal-ui
    restart: unless-stopped
    depends_on:
      temporal:
        condition: service_healthy
    environment:
      - TEMPORAL_ADDRESS=temporal:7233
      - TEMPORAL_CORS_ORIGINS=http://localhost:3000
    networks:
      - temporal-network
    ports:
      - "8080:8080"

networks:
  temporal-network:
    driver: bridge
    name: temporal-network

volumes:
  postgres_data:

Verifizieren: docker compose config --quiet darf keinen Fehler ausgeben. Wenn der Befehl ohne Ausgabe endet, ist die YAML-Syntax gültig.

Schritt 4: Stack starten

Starte alle Dienste im Hintergrund:

docker compose up -d

Der Start-Vorgang dauert je nach System und Download-Geschwindigkeit 2–5 Minuten. Die Reihenfolge ist vollständig durch depends_on-Bedingungen gesteuert: PostgreSQL muss gesund sein, bevor das Schema angelegt wird; der Temporal-Server wartet auf den erfolgreichen Abschluss des Schema-Setups; UI und Namespace-Container warten auf einen gesunden Server.

Logs aller Dienste live verfolgen:

docker compose logs -f

Verifizieren: Nach ca. 2–3 Minuten zeigt docker compose ps folgendes Bild:

NAME                       STATUS
temporal-postgresql        Up (healthy)
temporal-admin-tools       Exited (0)
temporal                   Up (healthy)
temporal-create-namespace  Exited (0)
temporal-ui                Up

Beide admin-tools-Container müssen mit Exit-Code 0 beendet sein (nicht 1 oder laufend). Der Temporal-Server und PostgreSQL müssen den Status healthy tragen. Ein anderer Exit-Code bei den Admin-Tools deutet auf ein Datenbankverbindungsproblem oder fehlende Skript-Dateien hin – prüfe dann mit docker compose logs temporal-admin-tools.

Schritt 5: Web-UI aufrufen und Namespace prüfen

Öffne http://localhost:8080 im Browser. Die Temporal Web-UI zeigt das Dashboard mit dem Namespace default. Unter Namespaces in der linken Navigation sollte „default" als aktiver Namespace gelistet sein. Ohne diesen Namespace können keine Workflows gestartet werden – sein Fehlen ist der häufigste Fehler bei der Erstinstallation.

Zusätzlich kannst du per curl prüfen, ob die UI antwortet:

curl -sI http://localhost:8080 | head -1

Erwartete Ausgabe: HTTP/1.1 200 OK oder HTTP/1.1 301 Moved Permanently.

Verifizieren: Browser zeigt das Temporal-Dashboard ohne Fehlermeldung „Unable to reach server". Namespace „default" ist unter Settings > Namespaces sichtbar. Der gRPC-Port ist erreichbar:

docker exec temporal nc -z localhost 7233 && echo "gRPC OK"

Erwartete Ausgabe: gRPC OK.

Schritt 6: Ersten Worker/Client verbinden

Dein Worker oder Client verbindet sich immer über Port 7233 des Docker-Hosts, Namespace default. Hier ein Verbindungsbeispiel für die gängigsten SDKs:

# Go:         client.Dial(client.Options{HostPort: "localhost:7233"})
# Python:     await Client.connect("localhost:7233")
# TypeScript: new Client({ connection: { address: "localhost:7233" } })
# Namespace ist immer "default" (ohne explizite Angabe bereits Standard)

Läuft dein Worker in einem anderen Docker-Container im selben Netzwerk (temporal-network), lautet die Adresse temporal:7233 statt localhost:7233. Füge dazu den Worker-Container dem Netzwerk temporal-network in der compose.yaml hinzu.

Einen zusätzlichen Namespace kannst du jederzeit anlegen:

docker exec temporal-admin-tools temporal operator namespace create mein-namespace --address temporal:7233

Verifizieren: Starte einen einfachen Worker und prüfe, ob er sich ohne Verbindungsfehler registriert. In docker compose logs temporal sollten keine ERROR-Einträge bezüglich fehlender Verbindungen erscheinen.

Schritt 7: Updates durchführen

Neue Temporal-Versionen erscheinen regelmäßig. Beim Update müssen Server- und Admin-Tools-Version immer identisch bleiben. Aktualisiere zuerst die Versionsnummern in der .env, dann:

# .env anpassen: TEMPORAL_VERSION, TEMPORAL_ADMINTOOLS_VERSION, TEMPORAL_UI_VERSION
docker compose pull
docker compose up -d

Das Schema-Update übernimmt der temporal-admin-tools-Container beim nächsten Start automatisch, sofern das Setup-Skript aufgerufen wird. Lese vor jedem Major-Versions-Update die offiziellen Release-Notes, da Datenbankmigrationen manchmal besondere Schritte erfordern.

Verifizieren: docker compose ps zeigt alle Dienste mit neuen Image-Tags. docker compose logs temporal | grep version gibt die neue Serverversion aus.

Troubleshooting / Typische Fehler

  1. „connection refused" oder „Unable to reach server" in der UI: Die Variable BIND_ON_IP=0.0.0.0 fehlt im temporal-Dienst. Ohne sie lauscht der Server nur auf 127.0.0.1 und ist von anderen Containern nicht erreichbar. Ergänzen und docker compose up -d erneut ausführen.
  2. „failed to load dynamic config": Das Verzeichnis ./dynamicconfig existiert nicht oder enthält keine development-sql.yaml. Lösung: ls dynamicconfig/ prüfen – die Datei muss vorhanden sein, bevor docker compose up aufgerufen wird. Sie kommt aus dem geklonten samples-server-Repository.
  3. admin-tools beendet sich mit Exit-Code 1: Das Skript ./scripts/setup-postgres.sh existiert nicht oder ist nicht ausführbar. Sicherstellen, dass das Repository vollständig geklont wurde und der scripts/-Ordner relativ zur compose.yaml liegt.
  4. „namespace not found" beim Workflow-Start: Der temporal-create-namespace-Container ist mit einem Fehler beendet oder wurde übersprungen. Mit docker compose logs temporal-create-namespace prüfen und ggf. manuell anlegen: docker exec temporal-admin-tools temporal operator namespace create default --address temporal:7233.
  5. Port-Konflikt auf 5432: Läuft lokal bereits PostgreSQL, ist der Port belegt. Den Host-Port in der compose.yaml auf 5433:5432 ändern – der interne Docker-Port 5432 bleibt gleich.
  6. Schema-Inkompatibilität nach Update: Tritt auf, wenn TEMPORAL_VERSION und TEMPORAL_ADMINTOOLS_VERSION unterschiedliche Werte haben. Immer beide Versionen synchron halten.
  7. Veraltetes auto-setup-Image verwendet: Viele Online-Tutorials zeigen noch temporalio/auto-setup. Dieses Image ist offiziell als deprecated markiert und erhält keine Sicherheitsupdates mehr. Immer auf temporalio/server + temporalio/admin-tools wechseln.
  8. Workflow-History-Limit überschritten: Ein einzelner Workflow darf standardmäßig maximal 50.000 History-Events haben. KI-Agenten-Loops mit Tausenden von Schritten erreichen dieses Limit. Lösung: das Continue-as-New-Pattern im Workflow-Code implementieren.
  9. Datenverlust nach docker compose down: Nur bei fehlendem Named Volume. Mit dem postgres_data-Volume in der Compose-Datei bleiben alle Daten erhalten – beim nächsten docker compose up werden sie automatisch wiederhergestellt.

Häufige Fragen

Kann ich Temporal für Produktions-Workloads mit Docker Compose betreiben?

Für kleine bis mittlere Deployments auf einem einzelnen Server: ja. Temporal selbst empfiehlt jedoch offiziell Kubernetes mit Helm-Charts (ab v0.73.1+ für Server 1.30+) für hohe Verfügbarkeit und horizontale Skalierung. Docker Compose ist ideal für Entwicklungsumgebungen, CI/CD-Pipelines und kleine Produktivinstallationen mit moderaten Workload-Anforderungen.

Wozu brauche ich Elasticsearch?

Nur für erweiterte Workflow-Sichtbarkeit: komplexe Such- und Filterabfragen über eigene Workflow-Attribute (sogenannte Search Attributes). Für die meisten Anwendungen reicht die PostgreSQL-only-Variante völlig aus. Elasticsearch erhöht den RAM-Bedarf auf mindestens 8 GB und macht den Stack deutlich komplexer.

Was ist der Unterschied zwischen Workflows und Activities?

Workflows sind deterministischer Orchestrierungs-Code: kein direkter Netzwerkzugriff, keine Zufallszahlen, keine Systemzeit (datetime.now()). Activities sind die eigentlichen Arbeitseinheiten – API-Aufrufe, Datenbankabfragen, Berechnungen – und können beliebig oft automatisch wiederholt werden. Dieser Trennung muss konsequent gefolgt werden: Alles mit Seiteneffekten gehört in Activities, der Ablauf gehört in Workflows.

Wie prüfe ich, ob Temporal korrekt läuft?

Drei unabhängige Checks: (1) docker compose ps – alle Dienste außer den beiden Admin-Tools sollten running/healthy sein, die Admin-Tools Exited (0). (2) curl -sI http://localhost:8080 | head -1 – Web-UI muss mit HTTP 200 antworten. (3) docker compose logs temporal | grep -E "Frontend started|Start service" – diese Meldungen bestätigen einen sauberen Server-Start.

Wie erstelle ich weitere Namespaces?

Über die Kommandozeile: docker exec temporal-admin-tools temporal operator namespace create mein-namespace --address temporal:7233. Alternativ über die Web-UI unter Settings > Namespaces > Create Namespace.

Unterstützen die offiziellen Images Apple Silicon (M1/M2)?

Ja, ab Temporal-Version 1.14.2+ werden die Images auch für linux/arm64 bereitgestellt. Auf einem Mac mit Apple Silicon läuft der Stack damit nativ ohne Rosetta-Emulation.

Fazit

Temporal löst ein echtes Problem in verteilten Systemen: fehlertolerante, zustandsbehaftete Workflows ohne selbst geschriebene Retry-Logik, Queuing-Infrastruktur oder Zustandsdatenbanken. Der Einstieg via Docker Compose ist überschaubar – das samples-server-Repository liefert alle nötigen Bausteine. Entscheidend sind drei Punkte: BIND_ON_IP=0.0.0.0 im Server-Container, das vorhandene dynamicconfig-Verzeichnis vor dem ersten Start und die identischen Versionen von Server und Admin-Tools. Wer Temporal produktiv mit hoher Last betreibt, sollte mittelfristig Kubernetes mit den offiziellen Helm-Charts evaluieren – für KMU-Szenarien und die Entwicklungsumgebung ist Docker Compose aber ein ausgezeichneter, schlanker Einstieg.

Für eine sichere Produktivumgebung empfiehlt sich die Absicherung des Docker-Stacks: Docker Compose absichern: Secrets, Healthchecks und Non-Root zeigt, wie du Passwörter aus der Compose-Datei herausnimmst und Container mit minimalen Rechten betreibst. Und weil Temporal auf PostgreSQL aufbaut: MySQL & PostgreSQL Backup automatisieren erklärt, wie du das postgres_data-Volume regelmäßig per pg_dump sicherst und in die Cloud überträgst.

Weiterführende Anleitungen und Quellen

  1. Docker Compose: Multi-Container-Stacks aufbauen – Grundlagen zu Compose-Syntax, depends_on und Healthchecks
  2. Docker-Netzwerke und Volumes richtig nutzen – Named Volumes und Bridge-Netzwerke verstehen
  3. PostgreSQL pg_dump und pg_restore – Backup und Migration der Temporal-Datenbank
  4. Windmill mit Docker installieren – alternative Developer-Workflow-Plattform im Vergleich
  5. n8n mit Docker: KI-Workflows und Automatisierung self-hosted – Low-Code-Automatisierung als Ergänzung zu Temporal

Offizielle Quellen: Temporalio Samples-Server-Repository (github.com/temporalio/samples-server/tree/main/compose), Temporal Self-Hosted Deployment Guide (docs.temporal.io/self-hosted-guide/deployment), Docker Hub: temporalio/server und temporalio/ui.