media-rip/Dockerfile
xpltd c9ad4fc5d0 R021/R022/R026: Docker, CI/CD, deployment example
Dockerfile (multi-stage):
- Stage 1: Node 22 builds frontend (npm ci + npm run build)
- Stage 2: Python 3.12 installs backend deps
- Stage 3: Slim runtime with ffmpeg + deno (yt-dlp needs both)
- Non-root user (mediarip), healthcheck, PYTHONUNBUFFERED
- Volumes: /downloads (media), /data (SQLite DB)

docker-compose.example.yml:
- Caddy reverse proxy with automatic TLS via Let's Encrypt
- Separate Caddyfile.example for domain configuration
- Health-dependent startup ordering
- Environment variables for admin setup

CI/CD (.github/workflows/):
- ci.yml: backend lint+test, frontend typecheck+test, Docker smoke
  build. Runs on PRs and pushes to main.
- publish.yml: multi-platform build (amd64+arm64), pushes to
  ghcr.io/xpltd/media-rip on v*.*.* tags. Semantic version tags
  (v1.0.0 → latest + 1.0.0 + 1.0 + 1). Auto GitHub Release.

.dockerignore: excludes dev artifacts, .gsd/, node_modules/, .venv/
2026-03-19 06:57:25 -05:00

66 lines
2.3 KiB
Docker

# media.rip() — multi-stage Docker build
# Stage 1: Build frontend (Node)
# Stage 2: Install backend deps (Python)
# Stage 3: Slim runtime with ffmpeg
#
# Image: ghcr.io/xpltd/media-rip
# Platforms: linux/amd64, linux/arm64
# ── Stage 1: Frontend build ──────────────────────────────────────────
FROM node:22-slim AS frontend-builder
WORKDIR /build/frontend
COPY frontend/package.json frontend/package-lock.json* ./
RUN npm ci --ignore-scripts
COPY frontend/ ./
RUN npm run build
# ── Stage 2: Python dependencies ─────────────────────────────────────
FROM python:3.12-slim AS python-deps
WORKDIR /build
COPY backend/requirements.txt ./
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
# ── Stage 3: Runtime ─────────────────────────────────────────────────
FROM python:3.12-slim AS runtime
# Install ffmpeg (required by yt-dlp for muxing/transcoding)
# Install deno (required by yt-dlp for YouTube JS interpretation)
RUN apt-get update && \
apt-get install -y --no-install-recommends ffmpeg curl unzip && \
curl -fsSL https://deno.land/install.sh | DENO_INSTALL=/usr/local sh && \
apt-get purge -y curl unzip && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/*
# Copy Python packages from deps stage
COPY --from=python-deps /install /usr/local
# Create non-root user
RUN useradd --create-home --shell /bin/bash mediarip
# Application code
WORKDIR /app
COPY backend/ ./
# Copy built frontend into backend static dir
COPY --from=frontend-builder /build/frontend/dist ./static
# Create default directories
RUN mkdir -p /downloads /data && \
chown -R mediarip:mediarip /app /downloads /data
USER mediarip
# Environment defaults
ENV MEDIARIP__DOWNLOADS__OUTPUT_DIR=/downloads \
MEDIARIP__DATABASE__PATH=/data/mediarip.db \
PYTHONUNBUFFERED=1
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/health')" || exit 1
CMD ["python", "-m", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]