diff --git a/Dockerfile b/Dockerfile index ae433f6..002ce9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,32 +1,39 @@ +# syntax=docker/dockerfile:1 + # Stage 1: Install build tools and Python dependencies FROM python:3.13-slim AS builder -RUN apt-get update && apt-get install -y --no-install-recommends \ +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ + apt-get update && apt-get install -y --no-install-recommends \ build-essential \ gcc \ python3-dev \ libopencv-dev \ - libmariadb-dev \ - && rm -rf /var/lib/apt/lists/* + libmariadb-dev WORKDIR /app COPY requirements.txt ./ -# Install dependencies into a venv using pip (no poetry needed) -RUN python -m venv /app/.venv && \ - /app/.venv/bin/pip install --no-cache-dir -r requirements.txt +# Install dependencies into a venv using uv (10-25x faster than pip) +RUN --mount=type=cache,target=/root/.cache/uv \ + python -m venv /app/.venv && \ + /app/.venv/bin/uv pip install -r requirements.txt # Stage 2: Runtime system dependencies (runs in parallel with builder) FROM python:3.13-slim AS runtime-base -RUN apt-get update && apt-get install -y --no-install-recommends \ - libgl1 \ +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ + apt-get update && apt-get install -y --no-install-recommends \ libglib2.0-0 \ tesseract-ocr \ tesseract-ocr-eng \ libmariadb3 \ - && rm -rf /var/lib/apt/lists/* + curl # Stage 3: Test — runtime deps + venv + test dependencies + run tests FROM runtime-base AS test @@ -36,7 +43,10 @@ WORKDIR /app COPY --from=builder /app/.venv /app/.venv ENV PATH="/app/.venv/bin:$PATH" -RUN pip install --no-cache-dir pytest pytest-asyncio pytest-xdist httpx aioresponses fakeredis +COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv + +RUN --mount=type=cache,target=/root/.cache/uv \ + uv pip install --python /app/.venv/bin/python pytest pytest-asyncio pytest-xdist httpx aioresponses fakeredis COPY . . @@ -45,6 +55,8 @@ RUN pytest tests/ -x -q # Stage 4: Final image — combine venv from builder + runtime base FROM runtime-base +RUN adduser --system --no-create-home appuser + WORKDIR /app # Copy the venv from the builder stage @@ -55,5 +67,13 @@ ENV PATH="/app/.venv/bin:$PATH" # Copy the application code COPY . . +RUN chown -R appuser /app + +USER appuser + EXPOSE 5001 + +HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=40s \ + CMD curl -f http://localhost:5001/api/status || exit 1 + CMD ["sh", "-c", "alembic upgrade head && uvicorn api.app:app --host 0.0.0.0 --port 5001 --no-server-header"]