Dockerfile
| 1 | # MuseHub — Production Dockerfile |
| 2 | # Multi-stage build: builder installs deps into wheels; runtime copies only the wheels. |
| 3 | # |
| 4 | # Layer invalidation guide (when to rebuild): |
| 5 | # requirements.txt changed → docker compose build musehub |
| 6 | # Python code changed → no rebuild (override.yml bind-mounts musehub/ tests/ etc.) |
| 7 | |
| 8 | FROM python:3.11-slim as builder |
| 9 | |
| 10 | WORKDIR /app |
| 11 | |
| 12 | RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 13 | build-essential \ |
| 14 | && rm -rf /var/lib/apt/lists/* |
| 15 | |
| 16 | COPY requirements.txt . |
| 17 | RUN pip wheel --no-cache-dir --no-deps --wheel-dir /app/wheels -r requirements.txt |
| 18 | |
| 19 | |
| 20 | FROM python:3.11-slim as runtime |
| 21 | |
| 22 | WORKDIR /app |
| 23 | |
| 24 | RUN groupadd -r musehub && useradd -r -g musehub musehub |
| 25 | |
| 26 | RUN apt-get update && apt-get install -y --no-install-recommends \ |
| 27 | libpq5 \ |
| 28 | && rm -rf /var/lib/apt/lists/* |
| 29 | |
| 30 | COPY --from=builder /app/wheels /wheels |
| 31 | RUN pip install --no-cache-dir /wheels/* |
| 32 | RUN pip install --no-cache-dir pytest-cov |
| 33 | |
| 34 | COPY --chown=musehub:musehub musehub/ ./musehub/ |
| 35 | COPY --chown=musehub:musehub tests/ ./tests/ |
| 36 | COPY --chown=musehub:musehub scripts/ ./scripts/ |
| 37 | COPY --chown=musehub:musehub alembic/ ./alembic/ |
| 38 | COPY --chown=musehub:musehub tourdeforce/ ./tourdeforce/ |
| 39 | COPY --chown=musehub:musehub alembic.ini pyproject.toml ./ |
| 40 | |
| 41 | RUN mkdir -p /data && chown -R musehub:musehub /data && chmod 755 /data |
| 42 | |
| 43 | USER musehub |
| 44 | |
| 45 | ENV PYTHONPATH=/app |
| 46 | ENV PYTHONDONTWRITEBYTECODE=1 |
| 47 | ENV PYTHONUNBUFFERED=1 |
| 48 | |
| 49 | EXPOSE 10003 |
| 50 | |
| 51 | CMD ["uvicorn", "musehub.main:app", "--host", "0.0.0.0", "--port", "10003"] |