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>
113 lines
3.5 KiB
YAML
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:
|