video_press/Dockerfile

99 lines
5 KiB
Text
Raw Permalink Normal View History

2026-03-09 17:42:26 -05:00
# =============================================================================
# VideoPress — Dockerfile
# =============================================================================
#
# Build:
# docker build -t videopress .
#
# Run (quick):
# docker run -d \
# -p 8080:8080 \
# -v /your/video/path:/media \
# --name videopress \
# videopress
#
# See docker-compose.yml for a fully-configured example.
# =============================================================================
# ── Stage 1: Python dependency builder ──────────────────────────────────────
FROM python:3.12-slim AS builder
WORKDIR /build
# Install build tools needed to compile gevent's C extensions
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libffi-dev \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
# Install into an isolated prefix so we can copy just the packages
RUN pip install --upgrade pip \
&& pip install --prefix=/install --no-cache-dir -r requirements.txt
# ── Stage 2: Runtime image ───────────────────────────────────────────────────
FROM python:3.12-slim
# ── System packages: ffmpeg (includes ffprobe) ───────────────────────────────
RUN apt-get update && apt-get install -y --no-install-recommends \
ffmpeg \
&& rm -rf /var/lib/apt/lists/*
# ── Copy Python packages from builder ────────────────────────────────────────
COPY --from=builder /install /usr/local
# ── Create a non-root application user ───────────────────────────────────────
# UID/GID 1000 is conventional and matches most Linux desktop users,
# which makes the volume-mapped files readable without extra chown steps.
RUN groupadd --gid 1000 appuser \
&& useradd --uid 1000 --gid 1000 --no-create-home --shell /sbin/nologin appuser
# ── Application code ─────────────────────────────────────────────────────────
WORKDIR /app
COPY app/ app/
COPY wsgi.py run.py gunicorn.conf.py requirements.txt ./
2026-03-09 17:42:26 -05:00
COPY templates/ templates/
COPY static/ static/
# ── Media volume mount point ──────────────────────────────────────────────────
# The host directory containing videos is mounted here at runtime.
# All file-system access by the application is restricted to this path.
RUN mkdir -p /media && chown appuser:appuser /media
# ── Data directory for the SQLite settings database ──────────────────────────
# Mounted as a named volume in docker-compose so settings survive restarts.
RUN mkdir -p /data && chown appuser:appuser /data
2026-03-09 17:42:26 -05:00
# ── File ownership ────────────────────────────────────────────────────────────
RUN chown -R appuser:appuser /app
# ── Switch to non-root user ───────────────────────────────────────────────────
USER appuser
# ── Environment defaults (all overridable via docker run -e or compose) ──────
# MEDIA_ROOT — the path inside the container where videos are accessed.
# Must match the container-side of your volume mount.
# PORT — TCP port Gunicorn listens on (exposed below).
# LOG_LEVEL — Gunicorn log verbosity (debug | info | warning | error).
ENV MEDIA_ROOT=/media \
DB_PATH=/data/videopress.db \
2026-03-09 17:42:26 -05:00
PORT=8080 \
LOG_LEVEL=info \
PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1
# ── Expose the web UI port ────────────────────────────────────────────────────
# The UI and API share the same port — no separate API port is needed.
EXPOSE 8080
# ── Health check ─────────────────────────────────────────────────────────────
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD python3 -c \
"import urllib.request; urllib.request.urlopen('http://localhost:8080/')" \
|| exit 1
# ── Start Gunicorn ────────────────────────────────────────────────────────────
CMD ["gunicorn", "-c", "gunicorn.conf.py", "wsgi:application"]