Dreistufiges Dockerfile mit standalone-Ausgabe; im Laufzeitabbild liegen weder Quelltext noch Bauwerkzeuge, und es läuft unter einem eigenen Benutzer. Die Migrationen erledigt ein eigener Einmaldienst aus der Bau-Stufe. Der Versuch, nur die Prisma-CLI ins Laufzeitabbild zu kopieren, scheiterte an ihren transitiven Modulen; sie alle mitzunehmen hätte das Abbild aufgebläht. Der Dienst läuft vor der App und muss sauber durchlaufen. Zwei Stellen mussten faul werden, weil Next beim Bauen Seitendaten sammelt und dabei Module lädt, die es zur Bauzeit noch ohne Umgebungsvariablen gibt: - Der Prisma-Client entsteht erst beim ersten Zugriff, über einen Proxy. - Die Auth.js-Konfiguration wird als Funktion übergeben. Ebenso liest prisma.config.ts die URL über process.env statt über env(), das beim Bauen ohne Datenbank abbricht. Dazu backup.sh, update.sh mit Rückrollpfad und scripts/release.sh. Der Dump wurde nachweislich in eine Wegwerf-Datenbank zurückgespielt und stimmt zeilengenau mit dem Original überein. Alle Skripte sind shellcheck-sauber. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
76 lines
2.4 KiB
YAML
76 lines
2.4 KiB
YAML
services:
|
|
db:
|
|
image: postgres:16-alpine
|
|
container_name: planer-db
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER:-planer}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt in .env}
|
|
POSTGRES_DB: ${POSTGRES_DB:-planer}
|
|
TZ: ${TZ:-Europe/Berlin}
|
|
volumes:
|
|
- db-daten:/var/lib/postgresql/data
|
|
ports:
|
|
- '${POSTGRES_PORT:-5432}:5432'
|
|
healthcheck:
|
|
test:
|
|
['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-planer} -d ${POSTGRES_DB:-planer}']
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 20s
|
|
|
|
# Einmaldienst: spielt die Migrationen ein und beendet sich. Läuft aus der
|
|
# Bau-Stufe, weil die Prisma-CLI eine Reihe Module braucht, die im schlanken
|
|
# Laufzeitabbild nichts zu suchen haben.
|
|
migration:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
target: bauen
|
|
container_name: planer-migration
|
|
restart: 'no'
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
TZ: ${TZ:-Europe/Berlin}
|
|
DATABASE_URL: postgresql://${POSTGRES_USER:-planer}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-planer}?schema=public
|
|
command: node node_modules/prisma/build/index.js migrate deploy
|
|
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
target: betrieb
|
|
container_name: planer-app
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
migration:
|
|
condition: service_completed_successfully
|
|
environment:
|
|
NODE_ENV: production
|
|
TZ: ${TZ:-Europe/Berlin}
|
|
INSTANZ: ${INSTANZ:?INSTANZ fehlt in .env}
|
|
APP_URL: ${APP_URL:?APP_URL fehlt in .env}
|
|
DATABASE_URL: postgresql://${POSTGRES_USER:-planer}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-planer}?schema=public
|
|
AUTH_SECRET: ${AUTH_SECRET:?AUTH_SECRET fehlt in .env}
|
|
AUTH_TRUST_HOST: ${AUTH_TRUST_HOST:-true}
|
|
ANMELDUNG_PASSWORT: ${ANMELDUNG_PASSWORT:-false}
|
|
OIDC_NAME: ${OIDC_NAME:-}
|
|
OIDC_ISSUER: ${OIDC_ISSUER:-}
|
|
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
|
|
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
|
|
WEBAUTHN_RP_ID: ${WEBAUTHN_RP_ID:?WEBAUTHN_RP_ID fehlt in .env}
|
|
WEBAUTHN_RP_NAME: ${WEBAUTHN_RP_NAME:-Planer}
|
|
WEBAUTHN_ORIGIN: ${WEBAUTHN_ORIGIN:?WEBAUTHN_ORIGIN fehlt in .env}
|
|
# Der Demo-Modus ist im Betrieb nie erlaubt.
|
|
DEMO_MODUS: 'false'
|
|
ports:
|
|
- '${APP_PORT:-3000}:3000'
|
|
|
|
volumes:
|
|
db-daten:
|