# syntax=docker/dockerfile:1 # Abschreib-Image fuer den CronJob apicore-job-voice-transcribe (Spec T7 6.3, # 11.1). Zur Laufzeit ohne Netz, ohne Schluessel, ohne Datenbank: das Image # enthaelt Python, faster-whisper, PyAV und das Modell `small`, sonst nichts. # # Base-Image per Digest gepinnt (python:3.12-slim, Multi-Arch-Index vom # 2026-10-16, Python 3.12.15). Ein Update ist ein bewusster Commit mit neuem # Digest, ermittelt per # docker buildx imagetools inspect python:3.12-slim ARG BASE_IMAGE=python:3.12-slim@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1 # --- Modell: feste Revision, jede Datei gegen ihre SHA-256 geprueft --------- FROM ${BASE_IMAGE} AS model WORKDIR /build COPY fetch_model.py ./ RUN python fetch_model.py /models/small # --- Abhaengigkeiten: nur Wheels, nur mit Hash (requirements.txt) ----------- FROM ${BASE_IMAGE} AS deps ENV PIP_DISABLE_PIP_VERSION_CHECK=1 PIP_NO_CACHE_DIR=1 RUN python -m venv /opt/venv COPY requirements.txt /tmp/requirements.txt RUN /opt/venv/bin/pip install --require-hashes --only-binary=:all: -r /tmp/requirements.txt # --- Tests: ohne bestandene Tests entsteht kein Image ----------------------- FROM deps AS test ENV PIP_DISABLE_PIP_VERSION_CHECK=1 PIP_NO_CACHE_DIR=1 PYTHONDONTWRITEBYTECODE=1 COPY requirements.txt requirements-test.txt /tmp/ RUN /opt/venv/bin/pip install --require-hashes --only-binary=:all: -r /tmp/requirements.txt -r /tmp/requirements-test.txt WORKDIR /app COPY transcribe.py fetch_model.py vocabulary.txt ./ COPY tests ./tests RUN /opt/venv/bin/python -m pytest -q -p no:cacheprovider tests && touch /app/.tests-passed # --- Laufzeit --------------------------------------------------------------- # Kein PYTHONUNBUFFERED/PYTHONDONTWRITEBYTECODE: `python -I` ignoriert PYTHON*- # Variablen; die Ausgabe sind wenige Zaehlerzeilen am Ende des Laufs. FROM ${BASE_IMAGE} AS runtime # uid/gid 1000 wie die Backend-Container: fetch, whisper und ingest teilen sich # das Arbeitsverzeichnis (Modus 0700/0600) und brauchen dieselbe Kennung. RUN groupadd --gid 1000 whisper \ && useradd --uid 1000 --gid 1000 --no-create-home --home-dir /tmp --shell /usr/sbin/nologin whisper ENV PATH=/opt/venv/bin:$PATH \ HOME=/tmp \ HF_HOME=/tmp/hf \ HF_HUB_OFFLINE=1 \ TRANSFORMERS_OFFLINE=1 \ WHISPER_MODEL_DIR=/models/small COPY --from=deps /opt/venv /opt/venv COPY --from=model /models /models WORKDIR /app COPY transcribe.py vocabulary.txt ./ # Haengt die Laufzeit an die Test-Stufe (BuildKit baut sonst nur, was gebraucht # wird), ohne dass etwas davon im Image landet. RUN --mount=type=bind,from=test,source=/app/.tests-passed,target=/mnt/tests-passed true USER 1000:1000 ENTRYPOINT ["python", "-I", "/app/transcribe.py"]