From 469de30c7bbd186cda1ab5b5957385101a4dbd77 Mon Sep 17 00:00:00 2001 From: CaffeineFueled Date: Mon, 25 May 2026 14:46:21 +0200 Subject: [PATCH] deploy: CHANGE Dockerfile to multilayer and distroless OS --- Dockerfile | 75 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 56 insertions(+), 19 deletions(-) diff --git a/Dockerfile b/Dockerfile index 71c1cfc..f1e013e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,28 +1,65 @@ -FROM python:3.11-slim +# syntax=docker/dockerfile:1.7 -# Create non-root user -RUN useradd -m -u 1000 appuser +# ============================================================================ +# Build stage: Debian 12's Python (paths/libs match the distroless runtime) +# ============================================================================ +# Don't use python:3.11-slim-bookworm — that image installs Python to /usr/local +# with an RPATH that breaks under distroless. Debian's apt python3 lives at the +# same paths as distroless's, so symlinks and libpython resolve correctly. +FROM debian:12-slim AS builder + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 \ + PIP_NO_CACHE_DIR=1 \ + PIP_DISABLE_PIP_VERSION_CHECK=1 + +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + python3 python3-pip python3-venv \ + && rm -rf /var/lib/apt/lists/* + +# Default (symlink) venv. /opt/venv/bin/python ends up as a symlink to +# /usr/bin/python3, which distroless also provides. +RUN python3 -m venv /opt/venv +ENV PATH=/opt/venv/bin:$PATH + +# Install runtime deps (cached layer — only rebuilt when requirements.txt changes) +COPY requirements.txt /tmp/requirements.txt +RUN pip install -r /tmp/requirements.txt + +# Pre-compile bytecode for faster cold start on a read-only rootfs +RUN python3 -m compileall -q /opt/venv + +# Pre-create writable mount points so the runtime rootfs can stay read-only. +# `uploads/` always needs to be writable; `logs/` only if LOGGING_ENABLED=true. +RUN mkdir -p /app/uploads /app/logs + +# ============================================================================ +# Runtime stage: distroless Python 3.11, non-root (uid 65532), no shell +# ============================================================================ +# gcr.io/distroless/python3-debian12 ships Python 3.11 with NO shell, NO +# package manager, and NO setuid binaries. The :nonroot tag pins USER to +# uid 65532 / gid 65532. +FROM gcr.io/distroless/python3-debian12:nonroot + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 -# Set working directory WORKDIR /app -# Copy requirements first for better caching -COPY requirements.txt . +# Venv ships its site-packages; bin/python is a symlink resolved by distroless's +# /usr/bin/python3 and Debian's libpython under /usr/lib. +COPY --from=builder --chown=nonroot:nonroot /opt/venv /opt/venv -# Install dependencies -RUN pip install --no-cache-dir -r requirements.txt +# Pre-created data dirs owned by the runtime user (mount writable volumes here) +COPY --from=builder --chown=nonroot:nonroot /app/uploads /app/uploads +COPY --from=builder --chown=nonroot:nonroot /app/logs /app/logs -# Copy only necessary files -COPY main.py . +# Application source — its own layer so app-only changes don't bust the dep cache +COPY --chown=nonroot:nonroot main.py /app/ -# Create uploads directory -RUN mkdir -p uploads && chown appuser:appuser uploads - -# Switch to non-root user -USER appuser - -# Expose port +USER nonroot EXPOSE 8000 -# Run the application -CMD ["python", "main.py"] +ENTRYPOINT ["/opt/venv/bin/python", "-m", "uvicorn"] +CMD ["main:app", "--host", "0.0.0.0", "--port", "8000"]