Files
everythingbutwork/docker-compose.yml
T
Raffael SheikhandClaude Opus 4.8 7285ed9cae Backup-Sidecar: täglicher pg_dump scharf geschaltet
Das dokumentierte Backup lief real nie (stock postgres-Image ohne Cron,
backup.sh nirgends eingebunden) -> bei Volume-/Disk-Verlust drohte Totalverlust.

- Neuer service "backup" (docker-compose.yml): postgres:16-alpine als Sidecar,
  taeglicher pg_dump um BACKUP_HOUR (Default 03:00 Europe/Berlin)
- backup-loop.sh: abhaengigkeitsfreier Tages-Scheduler (umgeht busybox-cron-
  Environment-Eigenheiten)
- backup.sh korrigiert: laeuft remote gegen PGHOST mit PGPASSWORD; -Fc statt
  "-Fc | gzip" (war doppelt komprimiert und als .sql.gz nicht restore-bar) -> .dump
- BACKUP_HOUR/BACKUP_RETENTION_DAYS konfigurierbar (.env.example)
- operations.md: Backup-/Restore-Anleitung an Ist-Zustand angepasst

Verifiziert: pg_dump erstellt + pg_restore in frische DB, Daten intakt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 11:09:38 +02:00

113 lines
3.5 KiB
YAML

# Production Docker-Compose. Deployment auf ToolCTRL-interne Infrastruktur.
# Erforderliche Env-Datei: .env.production (per Docker-Secret-Mount oder
# Compose-Override).
services:
postgres:
image: postgres:16-alpine
container_name: cockpit-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER:-cockpit}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB:-cockpit}
TZ: Europe/Berlin
volumes:
- cockpit_postgres_data:/var/lib/postgresql/data
- cockpit_backups:/backups
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER:-cockpit} -d $${POSTGRES_DB:-cockpit}']
interval: 10s
timeout: 5s
retries: 5
# Backup-Sidecar: täglicher pg_dump des postgres-Service nach cockpit_backups.
# Nutzt scripts/backup.sh (Custom-Format-Dump + Retention + API-Heartbeat),
# getaktet von scripts/backup-loop.sh. Stock postgres-Image → pg_dump passt
# versionsgenau (16) zur DB. Restore: siehe docs/operations.md.
backup:
image: postgres:16-alpine
container_name: cockpit-backup
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
POSTGRES_USER: ${POSTGRES_USER:-cockpit}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB:-cockpit}
PGHOST: postgres
API_URL: http://api:3000
CRON_BEARER_TOKEN: ${CRON_BEARER_TOKEN}
BACKUP_HOUR: ${BACKUP_HOUR:-03}
BACKUP_RETENTION_DAYS: ${BACKUP_RETENTION_DAYS:-14}
TZ: Europe/Berlin
volumes:
- cockpit_backups:/backups
- ./scripts/backup.sh:/usr/local/bin/backup.sh:ro
- ./scripts/backup-loop.sh:/usr/local/bin/backup-loop.sh:ro
entrypoint: ['/bin/sh', '/usr/local/bin/backup-loop.sh']
api:
build:
context: .
dockerfile: apps/api/Dockerfile
container_name: cockpit-api
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
NODE_ENV: production
DATABASE_URL: postgres://${POSTGRES_USER:-cockpit}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-cockpit}
AUTHENTIK_ISSUER: ${AUTHENTIK_ISSUER}
AUTHENTIK_CLIENT_ID: ${AUTHENTIK_CLIENT_ID}
AUTHENTIK_CLIENT_SECRET: ${AUTHENTIK_CLIENT_SECRET}
AUTHENTIK_REDIRECT_URI: ${AUTHENTIK_REDIRECT_URI}
SESSION_COOKIE_SECRET: ${SESSION_COOKIE_SECRET}
CRON_BEARER_TOKEN: ${CRON_BEARER_TOKEN}
PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-https://cockpit.tool-ctrl.de}
LOG_LEVEL: ${LOG_LEVEL:-info}
PORT: 3000
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://localhost:3000/api/health']
interval: 15s
timeout: 5s
retries: 3
web:
build:
context: .
dockerfile: apps/web/Dockerfile
container_name: cockpit-web
restart: unless-stopped
# Web ist statisches Asset-Image; Caddy mountet /srv aus diesem Container.
# In Compose teilen wir es via volume statt named-host.
volumes:
- cockpit_web_dist:/srv
caddy:
image: caddy:2-alpine
container_name: cockpit-caddy
restart: unless-stopped
depends_on:
- api
- web
ports:
- '80:80'
- '443:443'
environment:
COCKPIT_HOST: ${COCKPIT_HOST:-cockpit.tool-ctrl.de}
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- cockpit_web_dist:/srv:ro
- cockpit_caddy_data:/data
- cockpit_caddy_config:/config
volumes:
cockpit_postgres_data:
cockpit_backups:
cockpit_web_dist:
cockpit_caddy_data:
cockpit_caddy_config: