Bisher war Aktualisieren eine Folge von Befehlen aus der Anleitung, und zwei davon vergisst man zuverlaessig: die Sicherung vorher und die beiden SQL-Skripte hinterher. Genau die hat es hier schon gekostet. ./scripts/update.sh macht das in einem Durchgang - mit zwei Eigenschaften, auf die es ankommt: Bis zur Rueckfrage wird nichts veraendert. Der erste Entwurf hat die eigenen Aenderungen beiseite gelegt und danach am Serverzugriff abgebrochen - Halbzustand, aus dem man erst wieder herausfinden muss. Jetzt laufen Pruefung, Abgleich und Changelog-Anzeige vollstaendig durch, bevor irgendetwas angefasst wird. Eigene Aenderungen an versionierten Dateien blockieren nicht. Im Betrieb passt man die docker-compose.yml an, bis etwas laeuft; genau diese Anpassungen sind spaeter oft schon eingearbeitet. Das Skript legt sie mit git stash beiseite - rueckholbar, nicht weggeworfen - und sagt, wie man sie zurueckbekommt. Wer sie wirklich loswerden will, nimmt --verwerfen. Die .env bleibt immer unangetastet. Schlaegt die Sicherung fehl, wird nicht aktualisiert. Schlaegt der Bau fehl, nennt das Skript den Weg zurueck. Nebenbei behoben: Der Port der MinIO-Konsole stand fest auf 9001. Lief dort schon etwas, startete der ganze Stapel nicht. Jetzt ueber MINIO_KONSOLE_PORT einstellbar - dieselbe Moeglichkeit, die APP_PORT schon hatte. Aufgefallen beim Aufsetzen einer Testumgebung. Etappe: 8 Phase: Haertung
179 lines
6.9 KiB
YAML
179 lines
6.9 KiB
YAML
# =============================================================================
|
|
# Betreuungs-Cockpit - Produktivbetrieb
|
|
# =============================================================================
|
|
#
|
|
# docker compose up -d --build
|
|
#
|
|
# Kein Reverse Proxy in dieser Datei: der ist bereits vorhanden. Die
|
|
# Anwendung beendet selbst kein TLS und horcht standardmaessig nur auf
|
|
# 127.0.0.1:3000.
|
|
#
|
|
# Liegt der Proxy auf einem anderen Server, setze APP_BIND in der .env auf
|
|
# die Adresse, ueber die er herankommt - siehe docs/INSTALLATION.md,
|
|
# Schritt 7.
|
|
#
|
|
# Die Datenbank hat bewusst KEINE Portfreigabe. Sie ist nur ueber das
|
|
# interne Docker-Netz erreichbar. Wer mit psql heran muss, geht ueber
|
|
# docker compose exec db psql -U cockpit betreuungs_cockpit
|
|
# =============================================================================
|
|
|
|
name: betreuungs-cockpit
|
|
|
|
services:
|
|
db:
|
|
image: postgres:17-alpine
|
|
restart: unless-stopped
|
|
environment:
|
|
POSTGRES_USER: ${POSTGRES_USER:-cockpit}
|
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt in der .env}
|
|
POSTGRES_DB: ${POSTGRES_DB:-betreuungs_cockpit}
|
|
# Deutsche Sortierung und Zeichensatz - wichtig fuer Namenslisten
|
|
# und fuer die Volltextsuche mit der Konfiguration "german".
|
|
POSTGRES_INITDB_ARGS: '--encoding=UTF8 --locale=de_DE.UTF-8'
|
|
LANG: de_DE.UTF-8
|
|
volumes:
|
|
- postgres-daten:/var/lib/postgresql/data
|
|
- ./backups:/backups
|
|
healthcheck:
|
|
test: ['CMD-SHELL', 'pg_isready -U ${POSTGRES_USER:-cockpit} -d ${POSTGRES_DB:-betreuungs_cockpit}']
|
|
interval: 10s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 30s
|
|
networks: [intern]
|
|
# Kein "ports:" - die Datenbank ist von aussen nicht erreichbar.
|
|
|
|
minio:
|
|
# S3-kompatibler Objektspeicher fuer die Dokumente. Wer einen externen
|
|
# Speicher in der EU nutzt (z.B. Hetzner Object Storage), kann diesen
|
|
# Dienst weglassen und in der .env S3_ENDPOINT darauf zeigen lassen.
|
|
# Auch dann gilt: AV-Vertrag nach Art. 28 DSGVO abschliessen.
|
|
image: minio/minio:RELEASE.2025-01-20T14-49-07Z
|
|
restart: unless-stopped
|
|
command: server /daten --console-address ":9001"
|
|
environment:
|
|
MINIO_ROOT_USER: ${S3_ACCESS_KEY_ID:?S3_ACCESS_KEY_ID fehlt in der .env}
|
|
MINIO_ROOT_PASSWORD: ${S3_SECRET_ACCESS_KEY:?S3_SECRET_ACCESS_KEY fehlt in der .env}
|
|
MINIO_BROWSER_REDIRECT_URL: ${MINIO_KONSOLE_URL:-http://127.0.0.1:9001}
|
|
volumes:
|
|
- minio-daten:/daten
|
|
healthcheck:
|
|
test: ['CMD', 'mc', 'ready', 'local']
|
|
interval: 15s
|
|
timeout: 5s
|
|
retries: 10
|
|
start_period: 20s
|
|
ports:
|
|
# Nur an die Loopback-Adresse gebunden. Die Konsole erreichst du
|
|
# ueber einen SSH-Tunnel oder ueber deinen vorhandenen Proxy.
|
|
#
|
|
# Laeuft auf dem Server schon etwas auf 9001, weich in der .env aus:
|
|
# MINIO_KONSOLE_PORT=9011
|
|
- '${MINIO_KONSOLE_BIND:-127.0.0.1}:${MINIO_KONSOLE_PORT:-9001}:9001'
|
|
networks: [intern]
|
|
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: Dockerfile
|
|
args:
|
|
# In der Oberflaeche und unter /api/gesundheit sichtbar. Setzen mit:
|
|
# GIT_COMMIT=$(git rev-parse --short HEAD) docker compose up -d --build
|
|
GIT_COMMIT: ${GIT_COMMIT:-}
|
|
BUILD_ZEIT: ${BUILD_ZEIT:-}
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
minio:
|
|
condition: service_healthy
|
|
environment:
|
|
NODE_ENV: production
|
|
DATABASE_URL: postgresql://${POSTGRES_USER:-cockpit}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-betreuungs_cockpit}?schema=public&connection_limit=10
|
|
AUTH_SECRET: ${AUTH_SECRET:?AUTH_SECRET fehlt in der .env}
|
|
AUTH_URL: ${AUTH_URL:?AUTH_URL fehlt in der .env}
|
|
AUTH_TRUST_HOST: 'true'
|
|
ENC_KEY_V1: ${ENC_KEY_V1:?ENC_KEY_V1 fehlt in der .env - ohne ihn sind die verschluesselten Felder nicht lesbar}
|
|
# Bleibt leer, solange nicht rotiert wird. Die Anwendung ueberspringt
|
|
# leere Schluesselvariablen - siehe src/lib/env.ts.
|
|
# ENC_KEY_V2: ${ENC_KEY_V2:-}
|
|
ENC_KEY_AKTIV: ${ENC_KEY_AKTIV:-1}
|
|
INDEX_KEY: ${INDEX_KEY:?INDEX_KEY fehlt in der .env}
|
|
SESSION_MAX_AGE: ${SESSION_MAX_AGE:-1800}
|
|
REAUTH_MAX_AGE: ${REAUTH_MAX_AGE:-300}
|
|
LOGIN_MAX_VERSUCHE: ${LOGIN_MAX_VERSUCHE:-5}
|
|
LOGIN_FENSTER_SEKUNDEN: ${LOGIN_FENSTER_SEKUNDEN:-900}
|
|
LOGIN_SPERRE_SEKUNDEN: ${LOGIN_SPERRE_SEKUNDEN:-900}
|
|
SPEICHER_TREIBER: s3
|
|
S3_ENDPOINT: ${S3_ENDPOINT:-http://minio:9000}
|
|
S3_REGION: ${S3_REGION:-eu-central}
|
|
S3_BUCKET: ${S3_BUCKET:-betreuungs-cockpit}
|
|
S3_ACCESS_KEY_ID: ${S3_ACCESS_KEY_ID}
|
|
S3_SECRET_ACCESS_KEY: ${S3_SECRET_ACCESS_KEY}
|
|
UPLOAD_MAX_BYTES: ${UPLOAD_MAX_BYTES:-26214400}
|
|
OCR_AKTIV: ${OCR_AKTIV:-true}
|
|
SMTP_HOST: ${SMTP_HOST:-}
|
|
SMTP_PORT: ${SMTP_PORT:-587}
|
|
SMTP_USER: ${SMTP_USER:-}
|
|
SMTP_PASSWORD: ${SMTP_PASSWORD:-}
|
|
SMTP_FROM: ${SMTP_FROM:-}
|
|
TZ: Europe/Berlin
|
|
ports:
|
|
# Standard ist die Loopback-Adresse: dann erreicht die Anwendung nur
|
|
# ein Proxy, der auf demselben Rechner laeuft.
|
|
#
|
|
# Liegt der Reverse Proxy auf einem ANDEREN Server, muss hier die
|
|
# Adresse stehen, ueber die er herankommt - am besten die eines
|
|
# privaten Netzes oder eines WireGuard-Tunnels:
|
|
#
|
|
# APP_BIND=10.0.0.5
|
|
#
|
|
# 0.0.0.0 nur setzen, wenn eine Firewall den Port ausschliesslich
|
|
# fuer die IP des Proxy-Servers oeffnet. Die Anwendung beendet kein
|
|
# TLS und gehoert nie unverschluesselt ins offene Netz.
|
|
- '${APP_BIND:-127.0.0.1}:${APP_PORT:-3000}:3000'
|
|
networks: [intern]
|
|
healthcheck:
|
|
test: ['CMD', 'node', '-e', "fetch('http://127.0.0.1:3000/api/gesundheit').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 5
|
|
start_period: 40s
|
|
|
|
sicherung:
|
|
# Taeglich um 03:15 Uhr ein verschluesseltes Backup nach ./backups.
|
|
# Legt zusaetzlich die Pruefsumme ab und raeumt alte Staende auf.
|
|
image: postgres:17-alpine
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
environment:
|
|
PGHOST: db
|
|
PGUSER: ${POSTGRES_USER:-cockpit}
|
|
PGPASSWORD: ${POSTGRES_PASSWORD}
|
|
PGDATABASE: ${POSTGRES_DB:-betreuungs_cockpit}
|
|
SICHERUNG_PASSWORT: ${SICHERUNG_PASSWORT:?SICHERUNG_PASSWORT fehlt in der .env}
|
|
SICHERUNG_AUFBEWAHRUNG_TAGE: ${SICHERUNG_AUFBEWAHRUNG_TAGE:-30}
|
|
TZ: Europe/Berlin
|
|
volumes:
|
|
- ./backups:/backups
|
|
- ./scripts/sicherung.sh:/sicherung.sh:ro
|
|
- ./scripts/wiederherstellung.sh:/wiederherstellung.sh:ro
|
|
entrypoint: ['/bin/sh', '-c']
|
|
command:
|
|
- |
|
|
apk add --no-cache openssl coreutils >/dev/null
|
|
echo "15 3 * * * /bin/sh /sicherung.sh >> /backups/sicherung.log 2>&1" > /etc/crontabs/root
|
|
echo "Sicherungsdienst bereit. Naechster Lauf 03:15 Uhr."
|
|
crond -f -l 8
|
|
networks: [intern]
|
|
|
|
volumes:
|
|
postgres-daten:
|
|
minio-daten:
|
|
|
|
networks:
|
|
intern:
|
|
driver: bridge
|