110 lines
3.7 KiB
Docker
110 lines
3.7 KiB
Docker
# syntax=docker/dockerfile:1.7
|
|
# =============================================================================
|
|
# Stage 1: Build frontend (SvelteKit static output)
|
|
# =============================================================================
|
|
FROM node:22-alpine AS frontend-build
|
|
|
|
WORKDIR /build
|
|
|
|
# Cache npm install layer
|
|
COPY frontend/package.json frontend/package-lock.json ./
|
|
RUN npm ci
|
|
|
|
# Build static site
|
|
COPY frontend/ ./
|
|
RUN npm run build
|
|
|
|
# =============================================================================
|
|
# Stage 2: Build Python wheels + extract external dependency list
|
|
# =============================================================================
|
|
FROM python:3.12-slim AS python-build
|
|
|
|
WORKDIR /build
|
|
|
|
RUN pip install --no-cache-dir build
|
|
|
|
# Build core package wheel
|
|
COPY packages/core/ packages/core/
|
|
RUN python -m build packages/core/ --wheel --outdir /wheels
|
|
|
|
# Build server package wheel
|
|
COPY packages/server/ packages/server/
|
|
RUN python -m build packages/server/ --wheel --outdir /wheels
|
|
|
|
# Emit /wheels/deps.txt with ONLY external (PyPI) deps — filter out
|
|
# notify-bridge-* siblings, which are installed from local wheels below.
|
|
# This file is the cache key for the external-deps install layer: as long as
|
|
# pyproject.toml dependency lines don't change, the runtime install layer is
|
|
# served from registry buildcache and no wheels are re-downloaded.
|
|
RUN python <<'PY'
|
|
import tomllib
|
|
|
|
deps: list[str] = []
|
|
for p in ("packages/core/pyproject.toml", "packages/server/pyproject.toml"):
|
|
with open(p, "rb") as f:
|
|
data = tomllib.load(f)
|
|
for d in data["project"].get("dependencies", []):
|
|
if not d.lstrip().lower().startswith("notify-bridge-"):
|
|
deps.append(d)
|
|
|
|
seen: set[str] = set()
|
|
with open("/wheels/deps.txt", "w") as f:
|
|
for d in deps:
|
|
if d not in seen:
|
|
seen.add(d)
|
|
f.write(d + "\n")
|
|
PY
|
|
|
|
# =============================================================================
|
|
# Stage 3: Runtime
|
|
# =============================================================================
|
|
FROM python:3.12-slim
|
|
|
|
# uv — fast pip replacement. Installed from PyPI (Fastly CDN) rather than
|
|
# ghcr.io/astral-sh/uv, because GHCR pulls from this runner crawl at a few
|
|
# hundred KB/s and take longer than the install savings would recoup.
|
|
RUN pip install --no-cache-dir uv==0.11.7
|
|
|
|
ENV UV_COMPILE_BYTECODE=1 \
|
|
UV_LINK_MODE=copy
|
|
|
|
WORKDIR /app
|
|
|
|
# Install external deps first — layer cache key is deps.txt content, which
|
|
# only changes when pyproject.toml dependency lines change (not on version
|
|
# bumps). The cache mount persists downloaded wheels across local rebuilds;
|
|
# in CI, the registry buildcache serves the whole layer when unchanged.
|
|
COPY --from=python-build /wheels/deps.txt /tmp/deps.txt
|
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
uv pip install --system -r /tmp/deps.txt \
|
|
&& rm /tmp/deps.txt
|
|
|
|
# Install local wheels without re-resolving — all external deps are present.
|
|
COPY --from=python-build /wheels/*.whl /tmp/wheels/
|
|
RUN --mount=type=cache,target=/root/.cache/uv \
|
|
uv pip install --system --no-deps /tmp/wheels/*.whl \
|
|
&& rm -rf /tmp/wheels
|
|
|
|
# Copy frontend build
|
|
COPY --from=frontend-build /build/build/ /app/static/
|
|
|
|
# Create non-root user and data directory
|
|
RUN useradd --create-home --shell /bin/bash appuser \
|
|
&& mkdir -p /data \
|
|
&& chown appuser:appuser /data
|
|
|
|
# Environment defaults
|
|
ENV NOTIFY_BRIDGE_DATA_DIR=/data \
|
|
NOTIFY_BRIDGE_STATIC_DIR=/app/static \
|
|
NOTIFY_BRIDGE_DEBUG=false
|
|
|
|
VOLUME /data
|
|
EXPOSE 8420
|
|
|
|
USER appuser
|
|
|
|
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=10s \
|
|
CMD python -c "import os, urllib.request; urllib.request.urlopen(f'http://localhost:{os.environ.get(\"NOTIFY_BRIDGE_PORT\", 8420)}/api/health')"
|
|
|
|
CMD ["notify-bridge"]
|