@@ -14,15 +14,17 @@ FROM ghcr.io/astral-sh/uv:${UV_VERSION} AS uv
1414FROM python:3.13.1-slim AS base
1515
1616# Install security updates and minimal runtime dependencies
17- # Create non-root user (UID 10001 is common convention)
1817RUN apt-get update && \
1918 apt-get upgrade -y && \
2019 apt-get install -y --no-install-recommends \
21- ca-certificates \
22- curl && \
23- rm -rf /var/lib/apt/lists/* && \
24- groupadd -g 10001 appuser && \
25- useradd -u 10001 -g appuser -m -s /bin/bash appuser
20+ ca-certificates \
21+ curl && \
22+ rm -rf /var/lib/apt/lists/*
23+
24+ # Create non-root user and initialize /app with correct permissions
25+ RUN groupadd -g 10001 appuser && \
26+ useradd -u 10001 -g appuser -m -s /bin/bash appuser && \
27+ mkdir /app && chown appuser:appuser /app
2628
2729WORKDIR /app
2830
@@ -31,69 +33,56 @@ WORKDIR /app
3133# ============================================
3234FROM base AS builder
3335
34- # Install build dependencies (only needed during build)
3536RUN apt-get update && \
3637 apt-get install -y --no-install-recommends \
37- gcc \
38- g++ \
39- libpq-dev && \
38+ gcc \
39+ g++ \
40+ libpq-dev && \
4041 rm -rf /var/lib/apt/lists/*
4142
42- # Copy uv from uv stage (pinned version for reproducibility)
4343COPY --from=uv /uv /uvx /usr/local/bin/
4444
45- # Copy dependency files first for optimal layer caching
46- # Changes to source code won't invalidate this layer
45+ # Copy dependencies
4746COPY pyproject.toml uv.lock ./
4847
49- # Install dependencies with BuildKit cache mount for faster rebuilds
50- # --frozen: Use exact versions from uv.lock (reproducible builds)
51- # --no-dev: Exclude development dependencies
52- # --extra production: Include any production related dependencies (redis, aiocache etc...)
48+ # Install dependencies
5349RUN --mount=type=cache,target=/root/.cache/uv \
54- uv sync --frozen --no-default-groups --extra production --extra migrations
50+ uv sync --frozen --no-default-groups --extra production --extra migrations --no-install-project
5551
5652# ============================================
5753# Stage 3: Runtime - Production Image
5854# ============================================
5955FROM base AS runtime
6056
61- # Copy uv from builder stage (ensures version consistency)
57+ # Copy uv and the pre-built venv
6258COPY --from=builder /usr/local/bin/uv /usr/local/bin/uvx /usr/local/bin/
63-
64- # Copy installed dependencies from builder stage
65- # This excludes build tools (gcc, g++, libpq-dev)
6659COPY --from=builder /app/.venv /app/.venv
6760
68- # Copy application code
61+ # Copy application code with correct ownership
6962COPY --chown=appuser:appuser . .
7063
71- # Copy Docker-specific alembic config
64+ # Overwrite config
7265COPY --chown=appuser:appuser alembic.docker.ini alembic.ini
7366
74- # Create files directory with proper ownership
67+ # Create files directory
7568RUN mkdir -p /app/files && chown appuser:appuser /app/files
7669
77- # Switch to non-root user for security
70+ # Switch to non-root user
7871USER appuser
7972
8073# Environment variables
8174ENV APP_PORT=8000 \
8275 APP_RELOAD=false \
8376 PATH="/app/.venv/bin:$PATH" \
8477 PYTHONUNBUFFERED=1 \
85- PYTHONDONTWRITEBYTECODE=1
78+ PYTHONDONTWRITEBYTECODE=1 \
79+ UV_PROJECT_ENVIRONMENT="/app/.venv"
8680
8781# Expose application port
8882EXPOSE 8000
8983
90- # Health check using existing /health endpoint
91- # --interval=30s: Check every 30 seconds
92- # --timeout=5s: Mark unhealthy if no response in 5s
93- # --start-period=10s: Grace period for app startup
94- # --retries=3: Require 3 consecutive failures before marking unhealthy
9584HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
9685 CMD curl -f http://localhost:${APP_PORT:-8000}/health || exit 1
9786
98- # Use exec form for proper signal handling (graceful shutdown)
99- CMD ["uv" , "run" , "main.py" ]
87+ # FIX: Added --no-project to prevent uv from trying to write .egg-info
88+ CMD ["uv" , "run" , "--no-project" , "python" , " main.py" ]
0 commit comments