Files
swyxweb/Dockerfile
T

112 lines
4.9 KiB
Docker
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# syntax=docker/dockerfile:1
# SwyxWeb als ein Container: Das React-Frontend wird gebaut, in die statischen
# Ressourcen des Backends gelegt und zusammen mit ihm in ein Jar gepackt.
# Ausgeliefert wird am Ende alles über den einen Port des Backends (8080).
#
# Der eingebaute SwyxTray-Mock (/ws und /api/mock/**) läuft NICHT mit: seine
# Bohnen hängen am Spring-Profil "mock", und das setzt dieses Image nicht.
#
# Die beiden Build-Stufen laufen bewusst auf $BUILDPLATFORM, also nativ auf dem
# bauenden Rechner: JS-Bundle und Jar sind architekturunabhängig. Nur die
# Laufzeitstufe nutzt die Zielarchitektur.
# ---------------------------------------------------------------------------
# 1. Frontend bauen (Vite -> frontend/dist)
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM node:22-alpine AS frontend
WORKDIR /build
# Erst die Abhängigkeiten, damit diese Schicht im Cache bleibt, solange sich
# package.json/package-lock.json nicht ändern.
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ ./
# VITE_WS_URL nur setzen, wenn die Adresse fest ins Bundle soll; im Normalfall
# kommt sie zur Laufzeit aus /api/config (siehe README).
ARG VITE_WS_URL
RUN npm run build
# ---------------------------------------------------------------------------
# 2. Backend bauen (Spring Boot 4.1, Java 21) inkl. Frontend als static/
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM maven:3.9-eclipse-temurin-21 AS backend
WORKDIR /build
# Abhängigkeiten vorab auflösen – eigene Schicht, unabhängig vom Quelltext.
COPY backend/pom.xml ./
RUN --mount=type=cache,target=/root/.m2 \
mvn -B -q dependency:go-offline
COPY backend/src ./src
COPY --from=frontend /build/dist/ ./src/main/resources/static/
RUN --mount=type=cache,target=/root/.m2 \
mvn -B -DskipTests clean package \
&& cp target/*.jar /build/app.jar
# ---------------------------------------------------------------------------
# 3. Whisper-Modell einmalig ins Image laden, unabhängig von der Zielarchitektur.
# ---------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM python:3.12-slim-bookworm AS whisper-model
ENV HF_HUB_DISABLE_TELEMETRY=1
RUN pip install --no-cache-dir huggingface-hub==2.3.0
ARG WHISPER_MODEL_REPO=mobiuslabsgmbh/faster-whisper-large-v3-turbo
ARG WHISPER_MODEL_REVISION=0a363e9161cbc7ed1431c9597a8ceaf0c4f78fcf
RUN python -c 'import os; from huggingface_hub import snapshot_download; snapshot_download(os.environ["WHISPER_MODEL_REPO"], revision=os.environ["WHISPER_MODEL_REVISION"], local_dir="/models/whisper", allow_patterns=["*.json", "model.bin", "vocabulary.*", "README.md"])' \
&& rm -rf /models/whisper/.cache
# ---------------------------------------------------------------------------
# 4. Java + lokaler Whisper-Worker (glibc für CTranslate2/PyAV statt Alpine).
# ---------------------------------------------------------------------------
FROM eclipse-temurin:21-jre-noble AS runtime
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 python3-venv libgomp1 curl tini \
&& rm -rf /var/lib/apt/lists/* \
&& python3 -m venv /opt/whisper
ENV PATH="/opt/whisper/bin:$PATH"
COPY transcription/requirements.txt /app/transcription/requirements.txt
RUN pip install --no-cache-dir -r /app/transcription/requirements.txt && pip check
# Nicht als root laufen.
RUN groupadd --gid 10001 swyx \
&& useradd --uid 10001 --gid swyx --create-home swyx \
&& mkdir -p /data/transcriptions \
&& chown -R swyx:swyx /data
WORKDIR /app
COPY --from=backend --chown=swyx:swyx /build/app.jar ./app.jar
COPY --from=whisper-model /models/ ./models/
COPY transcription/service.py transcription/summary.py ./transcription/
COPY --chmod=755 docker/entrypoint.sh ./entrypoint.sh
USER swyx
EXPOSE 8080
VOLUME ["/data/transcriptions"]
# Adresse der SwyxTray-App zur Laufzeit überschreibbar (Spring Relaxed Binding):
# -e APP_WEBSOCKET_HOST=127.0.0.1 -e APP_WEBSOCKET_PORT=17654
# -e APP_WEBSOCKET_PATH=/ws -e APP_WEBSOCKET_SECURE=false
#
# SPRING_PROFILES_ACTIVE bleibt bewusst leer – der SwyxTray-Mock bliebe sonst
# beim Ausrollen erreichbar. Für eine Vorführung ohne Telefonanlage lässt er
# sich einzeln einschalten: -e SPRING_PROFILES_ACTIVE=mock
ENV JAVA_OPTS="-XX:MaxRAMPercentage=25.0" \
APP_TRANSCRIPTION_BASE_URL=http://127.0.0.1:8765 \
WHISPER_MODEL_PATH=/app/models/whisper \
WHISPER_DATA_DIR=/data/transcriptions \
WHISPER_THREADS=4 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
HF_HUB_OFFLINE=1 \
HF_HUB_DISABLE_TELEMETRY=1 \
TOKENIZERS_PARALLELISM=false
HEALTHCHECK --interval=30s --timeout=5s --start-period=90s --retries=3 \
CMD curl -fsS --max-time 2 http://127.0.0.1:8080/api/config >/dev/null \
&& curl -fsS --max-time 2 http://127.0.0.1:8765/health >/dev/null || exit 1
ENTRYPOINT ["/usr/bin/tini", "--", "/app/entrypoint.sh"]