Files
betreuungs-cockpit/Dockerfile
T
Florian Wilde 5ee3275112 fix: Betriebsskripte fehlten im Docker-Abbild
Das Verzeichnis scripts/ wurde beim Bauen nie in die Laufzeitstufe
uebernommen. Der in der Anleitung dokumentierte Befehl

    docker compose exec app node scripts/totp-geheimnis.mjs ...

endete deshalb mit "Cannot find module". Betroffen war nicht nur dieses
eine Skript, sondern alle, die im laufenden Behaelter gedacht sind - auch
wartungsschluessel.mjs und schluessel-erzeugen.mjs.

Kopiert wird jetzt das ganze Verzeichnis, nicht einzelne Dateien. Sonst
faellt beim naechsten Betriebsskript wieder auf, dass es fehlt - und zwar
erst dann, wenn man es braucht. Die Entwicklungsskripte darin laufen dort
mangels Werkzeugen nicht, kosten aber nur ein paar Kilobyte.

Geprueft im fertigen Abbild und gegen eine echte Datenbank: Das Skript
liegt unter /app/scripts, laeuft als Benutzer cockpit und gibt dasselbe
Geheimnis aus wie auf dem Entwicklungsrechner.

Die Anleitung nennt jetzt zusaetzlich den Weg fuer alle, die noch eine
aeltere Fassung laufen haben und nicht sofort aktualisieren wollen:
docker compose cp legt die Datei einmalig in den Behaelter.

Etappe: 8
Phase: Haertung
2026-08-22 12:02:16 +02:00

119 lines
4.6 KiB
Docker

# =============================================================================
# Betreuungs-Cockpit - Produktionsabbild
# =============================================================================
#
# Drei Stufen, damit im laufenden Abbild weder Quelltext noch Bauwerkzeuge
# liegen. Das Ergebnis sind rund 580 MB - der groesste Anteil davon sind
# Tesseract mit den deutschen Sprachdaten und die Prisma-Engines.
#
# Geprueft im fertigen Abbild: Node 22, Zeitzone Europe/Berlin,
# tesseract 5.5.2 mit Sprache deu, pdftoppm aus poppler-utils, Lauf als
# Benutzer cockpit (uid 1001), Migrationen und SQL-Skripte an Bord.
#
# Basis ist Alpine: kleiner Angriffsflaeche, und @node-rs/argon2 sowie
# Prisma bringen fertige musl-Binaerdateien mit.
# =============================================================================
# --- Stufe 1: Abhaengigkeiten -----------------------------------------------
FROM node:22-alpine AS abhaengigkeiten
WORKDIR /app
# Prisma und OpenSSL gehoeren zusammen.
RUN apk add --no-cache libc6-compat openssl
COPY package.json package-lock.json ./
COPY prisma ./prisma
# "npm ci" mit dem Lockfile - reproduzierbar, keine Ueberraschungen beim
# naechsten Bau. Der postinstall-Schritt erzeugt den Prisma-Client.
RUN npm ci --ignore-scripts \
&& npx prisma generate
# --- Stufe 2: Bauen ----------------------------------------------------------
FROM node:22-alpine AS bau
WORKDIR /app
RUN apk add --no-cache libc6-compat openssl
COPY --from=abhaengigkeiten /app/node_modules ./node_modules
COPY . .
# Beim Bauen werden keine echten Geheimnisse gebraucht: src/lib/env.ts
# prueft erst beim Zugriff. Diese Platzhalter erfuellen nur die Typen.
ENV NEXT_TELEMETRY_DISABLED=1
ENV SKIP_ENV_VALIDATION=1
# Git-Stand und Bauzeitpunkt landen in der Oberflaeche und im
# Gesundheitsendpunkt. Beim Aktualisieren sieht man damit auf einen Blick,
# ob wirklich der neue Stand laeuft:
#
# docker build --build-arg GIT_COMMIT=$(git rev-parse --short HEAD) .
ARG GIT_COMMIT=""
ARG BUILD_ZEIT=""
ENV NEXT_PUBLIC_GIT_COMMIT=$GIT_COMMIT
ENV NEXT_PUBLIC_BUILD_ZEIT=$BUILD_ZEIT
RUN npm run build
# --- Stufe 3: Laufzeit -------------------------------------------------------
FROM node:22-alpine AS laufzeit
WORKDIR /app
# tesseract-ocr + deutsche Sprachdaten fuer die Texterkennung,
# poppler-utils fuer pdftoppm (PDF-Seiten zu Bildern),
# tzdata fuer Europe/Berlin - sonst rechnet der Server in UTC und
# verschiebt Fristen um einen Tag.
RUN apk add --no-cache \
libc6-compat \
openssl \
tzdata \
tesseract-ocr \
tesseract-ocr-data-deu \
poppler-utils \
&& cp /usr/share/zoneinfo/Europe/Berlin /etc/localtime \
&& echo "Europe/Berlin" > /etc/timezone
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV TZ=Europe/Berlin
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
# Nicht als root laufen.
RUN addgroup --system --gid 1001 cockpit \
&& adduser --system --uid 1001 --ingroup cockpit cockpit
# Der Standalone-Build von Next.js bringt nur mit, was wirklich gebraucht wird.
COPY --from=bau --chown=cockpit:cockpit /app/.next/standalone ./
COPY --from=bau --chown=cockpit:cockpit /app/.next/static ./.next/static
COPY --from=bau --chown=cockpit:cockpit /app/public ./public
# Prisma-Schema, Migrationen und SQL-Skripte fuer "prisma migrate deploy"
# im laufenden Behaelter.
COPY --from=bau --chown=cockpit:cockpit /app/prisma ./prisma
COPY --from=bau --chown=cockpit:cockpit /app/node_modules/.prisma ./node_modules/.prisma
COPY --from=bau --chown=cockpit:cockpit /app/node_modules/@prisma ./node_modules/@prisma
COPY --from=bau --chown=cockpit:cockpit /app/node_modules/prisma ./node_modules/prisma
# Betriebsskripte, die im laufenden Behaelter gebraucht werden:
# totp-geheimnis.mjs zweites Geraet fuer den Zweitfaktor einrichten
# wartungsschluessel.mjs Schluessel fuer /api/wartung ausrechnen
# schluessel-erzeugen.mjs neue Schluessel fuer die Rotation
#
# Das ganze Verzeichnis, nicht einzelne Dateien: sonst faellt beim
# naechsten Betriebsskript wieder auf, dass es fehlt - und zwar erst dann,
# wenn man es braucht. Die Entwicklungsskripte darin laufen hier mangels
# Werkzeugen nicht, kosten aber auch nur ein paar Kilobyte.
COPY --from=bau --chown=cockpit:cockpit /app/scripts ./scripts
# Ablage fuer den Dateitreiber, falls kein Objektspeicher benutzt wird.
RUN mkdir -p /app/daten/dokumente && chown -R cockpit:cockpit /app/daten
USER cockpit
EXPOSE 3000
# Migrationen laufen beim Start, danach die Anwendung. Bewusst hier und
# nicht in einem eigenen Behaelter: so kann die Datenbank nie hinter dem
# Programmstand zurueckbleiben.
CMD ["sh", "-c", "node node_modules/prisma/build/index.js migrate deploy && node server.js"]