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 speichert jeden Workflow-Schritt in PostgreSQL, sodass kein Job nach Absturz oder Neustart verloren geht. Die Anleitung zeigt das Docker-Compose-Setup mit temporalio/server 1.32.1 und PostgreSQL 16, inklusive Update von 1.32.0.

Geprüft am 22.10.2026 · für temporal 1.32.1, temporal-ui 2.57.0

WerbelinksMit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Server-Rack mit grünen und blauen Status-LEDs und geordneten Netzwerkkabeln im Rechenzentrum

Temporal ist eine Open-Source-Plattform für Durable Execution: Der Workflow-Zustand wird nach jedem Schritt in einer Datenbank gespeichert; bricht ein Worker ab, läuft der Workflow dort weiter, ohne eigene Fehlerbehandlung. Typische Einsätze: verteilte Transaktionen (Saga-Pattern), langlaufende Prozesse, Zahlungsabwicklung, Onboarding und KI-Agenten. Die Anleitung gilt für jeden Linux-Host mit Docker.

Voraussetzungen

  1. Docker Engine >= 24.x und das Docker Compose Plugin >= 2.x müssen installiert sein. Prüfen Sie das mit docker compose version. Eine Installationsanleitung finden Sie unter Docker und Docker Compose auf Linux installieren.
  2. git zum Klonen des samples-server-Repositories (Skripte und dynamische Konfiguration sind Pflicht).
  3. Mindestens 2 CPU-Kerne und 4 GB freier RAM (Temporal-Server + PostgreSQL + UI; mit Elasticsearch: 8 GB empfohlen), x86-64 oder ARM64.
  4. Mindestens 10 GB freier Festplattenplatz für Images und das PostgreSQL-Daten-Volume.
  5. Internet-Zugang für den initialen Image-Download.
  6. Sicherheitshinweis: Temporal-Dienste dürfen niemals direkt im Internet erreichbar sein. Behandeln Sie sie wie eine Datenbank und betreiben Sie 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.32.1
Admin-Tools-Imagetemporalio/admin-tools:1.32.1
Web-UI-Imagetemporalio/ui:2.57.0
Datenbank-Imagepostgres:16
gRPC-Port (Pflicht)7233
Web-UI-Port8080
PostgreSQL-Port5432 (nur 127.0.0.1)
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. Klonen Sie es und wechseln Sie in das Unterverzeichnis:

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

Im Verzeichnis compose/ liegen fertige Varianten. Für PostgreSQL ohne Elasticsearch legen Sie im nächsten Schritt eine eigene compose.yaml auf Basis der docker-compose-postgres.yml an; Compose bevorzugt compose.yaml vor docker-compose.yml. scripts/ und dynamicconfig/ müssen relativ zum Compose-Verzeichnis liegen:

ls scripts/ dynamicconfig/

Erwartet werden setup-postgres.sh, create-namespace.sh und dynamicconfig/development-sql.yaml.

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, prüfen Sie, ob Sie im Verzeichnis samples-server/compose stehen.

Schritt 2: .env-Datei mit gepinnten Versionen anlegen

Ersetzen Sie die mitgelieferte .env durch folgenden Inhalt. Pinnen Sie konkrete Tags statt :latest, weil Schemaänderungen zwischen Versionen inkompatibel sein können. Wichtig: TEMPORAL_VERSION und TEMPORAL_ADMINTOOLS_VERSION müssen identisch sein.

# Temporal Docker Compose: Versionspinning
POSTGRESQL_VERSION=16
TEMPORAL_VERSION=1.32.1
TEMPORAL_ADMINTOOLS_VERSION=1.32.1
TEMPORAL_UI_VERSION=2.57.0

# Datenbank-Zugangsdaten: eigenes Passwort setzen (z. B. openssl rand -hex 24)
POSTGRES_USER=temporal
POSTGRES_PASSWORD=IHR_SICHERES_PASSWORT

Die Herstellerwerte (temporal/temporal) sind nur für Tests. Das Passwort muss vor dem ersten Start feststehen, PostgreSQL übernimmt es nur beim Anlegen des Volumes.

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

Schritt 3: compose.yaml anlegen

Legen Sie folgende compose.yaml an. Reihenfolge der fünf Dienste: PostgreSQL (Healthcheck), Schema-Setup durch temporal-admin-tools, dann temporal; sobald er gesund ist, folgen Namespace und UI.

services:
  postgresql:
    image: postgres:${POSTGRESQL_VERSION:-16}
    container_name: temporal-postgresql
    restart: unless-stopped
    ports:
      - "127.0.0.1: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.32.1}
    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.32.1}
    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.32.1}
    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.57.0}
    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:

Der PostgreSQL-Port ist nur an 127.0.0.1 gebunden; Temporal greift über das interne Docker-Netz zu.

Verifizieren: docker compose config --quiet darf keinen Fehler ausgeben und endet mit Exit-Code 0 (echo $?). Weil im Ordner auch die mitgelieferte docker-compose.yml liegt, gibt Compose hier und bei jedem weiteren Befehl zwei Warnzeilen aus: Found multiple config files with supported names: …/compose.yaml, …/docker-compose.yml und Using …/compose.yaml. Das ist erwartet, Compose verwendet die compose.yaml.

Schritt 4: Stack starten

Starten Sie alle Dienste im Hintergrund:

docker compose up -d

Der Start dauert 2 bis 5 Minuten; die Reihenfolge steuern die depends_on-Bedingungen.

Logs aller Dienste live verfolgen:

docker compose logs -f

Verifizieren: Nach ca. 2 bis 3 Minuten zeigt docker compose ps -a --format 'table {{.Name}}\t{{.Status}}' nach den beiden Warnzeilen aus Schritt 3 folgendes Bild. Ohne -a fehlen die beendeten admin-tools-Container in der Liste.

NAME                        STATUS
temporal                    Up 9 seconds (healthy)
temporal-admin-tools        Exited (0) 10 seconds ago
temporal-create-namespace   Exited (0) 3 seconds ago
temporal-postgresql         Up 33 seconds (healthy)
temporal-ui                 Up 3 seconds

Beide admin-tools-Container müssen mit Exit-Code 0 beendet sein, Server und PostgreSQL healthy. Ein anderer Exit-Code deutet auf Datenbankverbindung oder fehlende Skripte; prüfen Sie docker compose logs temporal-admin-tools.

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

Öffnen Sie http://localhost:8080. Unter Namespaces muss „default“ als aktiv gelistet sein; ohne ihn lassen sich keine Workflows starten.

Prüfung per curl:

curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080

Erwartet: 200. Nutzen Sie GET: Im Test mit UI 2.57.0 lieferte eine HEAD-Anfrage (curl -I) 405 Method Not Allowed, obwohl die UI im Browser lädt.

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

Worker und Clients verbinden sich über Port 7233 des Docker-Hosts, Namespace default:

# 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 der Worker als Container im Netz temporal-network, lautet die Adresse temporal:7233; nehmen Sie ihn dazu in der compose.yaml in dieses Netz auf.

Weitere Namespaces legen Sie mit einem kurzlebigen Admin-Tools-Container an (temporal-admin-tools ist nach dem Setup beendet, docker exec geht nicht):

docker compose run --rm --entrypoint temporal temporal-admin-tools \
  operator namespace create --namespace mein-namespace --address temporal:7233

Verifizieren: Starten Sie einen einfachen Worker und prüfen Sie, 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

Server- und Admin-Tools-Version müssen gleich bleiben. Ändern Sie zuerst die Versionen 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 neue temporal-admin-tools-Container per update-schema. Vorher Release Notes lesen und die Datenbank per pg_dump sichern.

Von 1.31 auf 1.32: In der .env TEMPORAL_VERSION und TEMPORAL_ADMINTOOLS_VERSION auf 1.32.0, TEMPORAL_UI_VERSION auf 2.55.0, dann docker compose pull und docker compose up -d. Laut Release Notes ist der vereinheitlichte Query Converter für Visibility-Abfragen jetzt aktiv: Er lehnt Vergleiche mit falschem Datentyp (etwa CustomKeyword = 123) und Text-Attribute gegen leeren String ab; prüfen Sie eigene List-Filter. Übergangsweise holt system.visibilityEnableUnifiedQueryConverter: false in dynamicconfig/development-sql.yaml den alten zurück, mit 1.33 entfällt er. Activity Eager Execution ist standardmäßig an, Standalone Activities sind allgemein verfügbar. Die alten Worker-Versioning-APIs (Build-ID-Kompatibilität) sind letztmals enthalten; vor 1.33 auf die Worker Deployment APIs migrieren. Search Attributes verwalten Sie mit der temporal-CLI statt tctl. Im Test (Oktober 2026) lief 1.31.3 auf 1.32.0 ohne Eingriff: keine ausstehenden Schema-Updates, nach rund 20 Sekunden wieder bereit.

Von 1.32.0 auf 1.32.1: In der .env TEMPORAL_VERSION und TEMPORAL_ADMINTOOLS_VERSION auf 1.32.1, TEMPORAL_UI_VERSION auf 2.57.0, dann docker compose pull und docker compose up -d. Server 1.32.1 behebt laut Release Notes Fehler und ändert das Datenbankschema nicht. Die Temporal-CLI in admin-tools wechselt dabei von 1.9.0 auf 1.9.1. Deren Release Notes nennen gegenüber 1.8.3 drei Breaking Changes: temporal activity unpause kennt --reset-attempts und --reset-heartbeats nicht mehr, temporal activity describe -o json liefert die Felder eine Ebene tiefer unter info, und operator namespace update --active-cluster lässt sich nicht mehr mit anderen Optionen kombinieren. Prüfen Sie eigene Skripte, die diese Befehle nutzen. UI 2.56.0 wertet den Header X-HTTP-Method-Override nicht mehr aus (CVE-2026-37236) und kann eingehende Verbindungen optional per mTLS absichern. UI 2.57.0 bringt ein optionales Umgebungsbanner (TEMPORAL_UI_BANNER_TEXT, TEMPORAL_UI_BANNER_COLOR). Neue Pflichtvariablen gibt es nicht. Im Test (Oktober 2026) lief 1.32.0 auf 1.32.1 ohne Eingriff: temporal-admin-tools endete mit Exit-Code 0 und meldete found zero updates from current version 1.19 (Visibility-Datenbank: 1.14), der Server war 12 Sekunden nach docker compose up -d wieder bereit, Namespaces und Workflows samt Signalen blieben erhalten.

Verifizieren: docker compose images zeigt die neuen Image-Tags, docker compose ps -a meldet temporal wieder als healthy und temporal-admin-tools mit Exited (0). docker exec temporal temporal-server --version nennt die laufende Serverversion, im Test temporal version 1.32.1.

Troubleshooting / Typische Fehler

  1. „dependency failed to start: container temporal is unhealthy“: BIND_ON_IP=0.0.0.0 fehlt im temporal-Dienst. Der Server lauscht dann nur auf der Container-IP statt auf allen Adressen, der Healthcheck nc -z localhost 7233 schlägt fehl und temporal bleibt bei (health: starting). Im Test brach docker compose up -d nach rund fünfeinhalb Minuten mit dieser Meldung ab, temporal stand danach auf (unhealthy). Zeile ergänzen, docker compose up -d.
  2. „unable to create dynamic config client: unable to validate dynamic config“: Die in DYNAMIC_CONFIG_FILE_PATH genannte Datei fehlt, die Meldung endet mit no such file or directory und der Server beendet sich mit Exit-Code 1. ./dynamicconfig/development-sql.yaml stammt aus samples-server, siehe Schritt 1.
  3. admin-tools endet mit Exit-Code 1: ./scripts/setup-postgres.sh fehlt oder ist nicht ausführbar, siehe Schritt 1.
  4. „namespace not found“: temporal-create-namespace ist fehlgeschlagen. docker compose logs temporal-create-namespace prüfen, ggf. manuell anlegen: docker compose run --rm --entrypoint temporal temporal-admin-tools operator namespace create --namespace default --address temporal:7233.
  5. Port-Konflikt auf 5432: Host-Port in der compose.yaml auf 127.0.0.1:5433:5432 ändern.
  6. Schema-Inkompatibilität nach Update: TEMPORAL_VERSION und TEMPORAL_ADMINTOOLS_VERSION unterscheiden sich; synchron halten.
  7. Veraltetes auto-setup-Image: temporalio/auto-setup ist deprecated; nutzen Sie temporalio/server und temporalio/admin-tools.
  8. Workflow-History-Limit überschritten: Standardmäßig maximal 51.200 Events (50 × 1024) oder 50 MB je Workflow; lange KI-Agenten-Loops erreichen das. Lösung: Continue-as-New.
  9. Datenverlust nach docker compose down: Nur ohne Named Volume oder mit -v; postgres_data bleibt sonst erhalten.

Häufige Fragen

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

Für kleine bis mittlere Installationen auf einem Server: ja. Für Hochverfügbarkeit und Skalierung bietet Temporal Helm-Charts für Kubernetes.

Wozu brauche ich Elasticsearch?

Nur für erweiterte Suche über eigene Workflow-Attribute (Search Attributes). Meist reicht PostgreSQL; Elasticsearch erhöht den RAM-Bedarf auf mindestens 8 GB.

Was ist der Unterschied zwischen Workflows und Activities?

Workflows sind deterministischer Orchestrierungs-Code: kein Netzwerkzugriff, keine Zufallszahlen, keine Systemzeit (datetime.now()). Activities sind die Arbeitseinheiten (API-Aufrufe, Datenbankabfragen) und werden automatisch wiederholt. Seiteneffekte gehören in Activities.

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

Siehe Schritt 4 und 5: docker compose ps -a, curl auf Port 8080, nc -z auf Port 7233.

Wie erstelle ich weitere Namespaces?

Mit dem Befehl aus Schritt 6, etwa --namespace mein-namespace.

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

Ja, die Images gibt es für linux/amd64 und linux/arm64; auf Apple Silicon läuft der Stack nativ.

Fazit

Temporal liefert fehlertolerante Workflows ohne eigene Retry-Logik. Entscheidend sind BIND_ON_IP=0.0.0.0, das dynamicconfig-Verzeichnis vor dem ersten Start und gleiche Versionen von Server und Admin-Tools. Bei hoher Last folgt Kubernetes mit Helm-Charts.

Zur Absicherung des Stacks: Docker Compose absichern: Secrets, Healthchecks und Non-Root zeigt, wie Sie Passwörter aus der Compose-Datei herausnehmen und Container mit minimalen Rechten betreiben. Zur Datensicherung: MySQL & PostgreSQL Backup automatisieren erklärt, wie Sie die Temporal-Datenbanken regelmäßig per pg_dump sichern und extern ablegen.

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. Release Notes: Temporal Server v1.32.1, Temporal UI v2.56.0, Temporal UI v2.57.0, Temporal CLI v1.9.1.