Ctrl K
ComunidadGuías…

Dockerfile

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# syntax=docker/dockerfile:1
#
# All-in-one tvtimes image: the FastAPI API, the arq worker, and the built web
# app in one container. `docker compose` runs it twice — once as the web/API
# process, once (command: worker) as the background worker.
#
#   docker build -t issinoho1969/tvtimes .
#
# Published multi-arch by .github/workflows/release.yml on a `v*` tag.

# --- stage 1: build the SPA -------------------------------------------------
FROM node:22-slim AS web
WORKDIR /web
COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci || npm install
COPY frontend/ ./
# Same-origin build: the client talks to /api on whatever host serves it.
RUN npm run build

# --- stage 2: python runtime --------------------------------------------------
FROM python:3.12-slim AS runtime
# Release tag, passed by .github/workflows/release.yml; "dev" for a plain build.
ARG TVTIMES_VERSION=dev
ENV PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1 \
    UV_COMPILE_BYTECODE=1 \
    UV_LINK_MODE=copy \
    TVTIMES_STATIC_DIR=/app/web \
    TVTIMES_VERSION=$TVTIMES_VERSION
WORKDIR /app

COPY --from=ghcr.io/astral-sh/uv:0.10 /uv /bin/uv

# gosu lets the entrypoint start as root (to take ownership of a bind-mounted
# /data) and drop to the unprivileged app user before exec'ing anything.
RUN apt-get update \
    && apt-get install -y --no-install-recommends gosu \
    && rm -rf /var/lib/apt/lists/* \
    && gosu nobody true

# Runtime dependencies, resolved straight from backend/pyproject.toml + uv.lock
# so those are the single source of truth (no hand-kept list to drift, as it
# did when defusedxml was added). --frozen fails the build loudly if the lock
# is stale rather than silently installing something else; --no-emit-project
# skips the app package itself (its source is COPYed below); --no-deps on the
# install trusts the already-transitive export. Its own layer, so it caches
# across app-code changes.
COPY backend/pyproject.toml backend/uv.lock ./
RUN uv export --frozen --no-dev --no-emit-project --no-hashes \
        --format requirements-txt -o /tmp/requirements.txt \
    && uv pip install --system --no-deps -r /tmp/requirements.txt \
    && rm /tmp/requirements.txt

COPY backend/ ./
COPY --from=web /web/dist ./web
COPY docker/entrypoint.sh /usr/local/bin/entrypoint
RUN chmod +x /usr/local/bin/entrypoint \
    && useradd --system --uid 10001 --home /app tvtimes \
    && mkdir -p /data && chown -R tvtimes:tvtimes /app /data

# No `USER` — the entrypoint starts as root, chowns /data (usually a fresh
# bind mount), then re-execs itself as `tvtimes` via gosu. An operator who
# wants a non-root PID 1 can still set `user:` in compose; the entrypoint
# then skips the chown and fails loudly if /data isn't writable.

EXPOSE 8000
ENTRYPOINT ["entrypoint"]
CMD ["web"]