# syntax=docker/dockerfile:1 # ---------------------------------------------------------------- web UI # # Pinned to the build host's architecture, not the target's. The output is static JS and # CSS, identical whatever it was built on, so there is nothing to gain from running npm # under emulation -- and a great deal to lose: an emulated arm64 npm build is minutes of # wall clock for a byte-identical result. FROM --platform=$BUILDPLATFORM node:22-slim AS web WORKDIR /web # Lockfile first, so a source edit does not reinstall node_modules. COPY web/package.json web/package-lock.json ./ RUN npm ci COPY web/ ./ RUN npm run build # ---------------------------------------------------------------- python deps # # This one does have to match the target: asyncpg, argon2-cffi and uvloop ship compiled # wheels, so the venv is architecture-specific. FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim AS builder ENV UV_COMPILE_BYTECODE=1 \ UV_LINK_MODE=copy \ UV_PYTHON_DOWNLOADS=never WORKDIR /app COPY pyproject.toml uv.lock README.md ./ COPY src ./src # From the lock, exactly: the set that was tested is the set that ships. RUN --mount=type=cache,target=/root/.cache/uv \ UV_PROJECT_ENVIRONMENT=/opt/venv uv sync --frozen --no-dev --no-editable # ---------------------------------------------------------------- runtime FROM python:3.12-slim-trixie # Which commit produced this image. Stamped by CI and logged on every boot, so # "did my repull actually take?" is answerable from the host without guessing at # timestamps -- a question that came up twice before this existed. ARG GIT_SHA=unknown ENV PATH="/opt/venv/bin:$PATH" \ PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ WEB_DIR=/app/web \ PODARIUM_BUILD=$GIT_SHA # ffmpeg is for trimming silence and levelling loudness after a download. It is the # largest thing in this image by some way (~100 MB unpacked); without it those settings # report themselves unavailable and everything else works exactly as before. # # trixie, not bookworm, for its ffmpeg 7.1. The silenceremove filter was rewritten # between 5.1 and 7: on 5.1 the same options cut every pause in speech down to a # quarter of a second, and there is no set of options that makes 5.1 keep a pause # whole. The trimming code refuses anything older than 7. RUN apt-get update && \ apt-get install -y --no-install-recommends curl ffmpeg && \ rm -rf /var/lib/apt/lists/* WORKDIR /app COPY --from=builder /opt/venv /opt/venv COPY --from=web /web/dist ./web COPY src ./src COPY alembic ./alembic COPY alembic.ini ./ COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN chmod +x /usr/local/bin/docker-entrypoint.sh EXPOSE 8044 # The stack runs this as 1026:100 to match the NFS share, so no USER is baked in here. HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ CMD curl -fsS http://127.0.0.1:8044/healthz || exit 1 ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]