deploy(docker): utente non root e versioni base pinnate (#38)
Punto 1: useradd -u 10001 app, chown /app (+ /app/uploads sul server), USER app in tutti e tre i Dockerfile. Stesso UID sul server e sul worker di visione, che condividono il volume uploads in sola lettura (punto 13). Punto 2: python:3.11.16-slim (server, client), python:3.13.15-slim (vision), ghcr.io/astral-sh/uv:0.10.9 (versione locale di `uv --version`). Dockerfile.frontend: TailwindCSS ora si compila in uno stage separato dall'immagine ufficiale node:20.20.2-bookworm-slim, non più con `curl | bash` su nodesource nell'immagine finale. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+9
-3
@@ -1,7 +1,7 @@
|
|||||||
FROM python:3.11-slim AS base
|
FROM python:3.11.16-slim AS base
|
||||||
|
|
||||||
# Install uv (fast Python package manager) from official slim image.
|
# Install uv (fast Python package manager) from official slim image.
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
|
COPY --from=ghcr.io/astral-sh/uv:0.10.9 /uv /uvx /usr/local/bin/
|
||||||
|
|
||||||
# System libs required by WeasyPrint at runtime.
|
# System libs required by WeasyPrint at runtime.
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
@@ -13,6 +13,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
shared-mime-info \
|
shared-mime-info \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Non-root user the app runs as at runtime.
|
||||||
|
RUN useradd -u 10001 app
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy lockfile + project metadata first to maximize Docker layer cache.
|
# Copy lockfile + project metadata first to maximize Docker layer cache.
|
||||||
@@ -27,7 +30,10 @@ RUN uv sync --frozen --no-dev --extra server
|
|||||||
COPY src/ ./src/
|
COPY src/ ./src/
|
||||||
|
|
||||||
# Uploads directory (mounted as a volume in production).
|
# Uploads directory (mounted as a volume in production).
|
||||||
RUN mkdir -p /app/uploads/images /app/uploads/pdfs /app/uploads/logos /app/uploads/reports
|
RUN mkdir -p /app/uploads/images /app/uploads/pdfs /app/uploads/logos /app/uploads/reports \
|
||||||
|
&& chown -R app:app /app
|
||||||
|
|
||||||
|
USER app
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
|
|||||||
+27
-20
@@ -1,13 +1,25 @@
|
|||||||
FROM python:3.11-slim AS base
|
# TailwindCSS built in its own stage, from the official Node image, instead
|
||||||
|
# of `curl | bash` against nodesource inside the final image (point 2, C2).
|
||||||
|
FROM node:20.20.2-bookworm-slim AS tailwind-build
|
||||||
|
|
||||||
|
WORKDIR /app/flask_app
|
||||||
|
COPY src/frontend/flask_app/ ./
|
||||||
|
|
||||||
|
# Versione esatta, non `tailwindcss@3`. Con il vincolo aperto ogni ricostruzione
|
||||||
|
# dell'immagine poteva prendere una minor diversa e produrre un CSS diverso senza
|
||||||
|
# che nessuno l'avesse validato: per un sistema che produce evidenze per audit
|
||||||
|
# ISO 9001 / IATF 16949 è lo stesso problema che il punto 12 risolve per le
|
||||||
|
# librerie del browser. Aggiornarla è una decisione, non un effetto collaterale.
|
||||||
|
RUN npm install tailwindcss@3.4.19 && \
|
||||||
|
npx tailwindcss -i static/css/input.css -o static/css/tailwind.css --minify
|
||||||
|
|
||||||
|
FROM python:3.11.16-slim AS base
|
||||||
|
|
||||||
# uv from the official slim image (fast Python package manager).
|
# uv from the official slim image (fast Python package manager).
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
|
COPY --from=ghcr.io/astral-sh/uv:0.10.9 /uv /uvx /usr/local/bin/
|
||||||
|
|
||||||
# Node.js 20 is needed at build time to compile TailwindCSS.
|
# Non-root user the app runs as at runtime.
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \
|
RUN useradd -u 10001 app
|
||||||
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
|
|
||||||
&& apt-get install -y --no-install-recommends nodejs \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
@@ -16,22 +28,17 @@ COPY pyproject.toml uv.lock ./
|
|||||||
COPY .python-version ./
|
COPY .python-version ./
|
||||||
RUN uv sync --frozen --no-dev --extra client
|
RUN uv sync --frozen --no-dev --extra client
|
||||||
|
|
||||||
# Copy the Flask app sources.
|
# Copy the Flask app sources, then overlay the TailwindCSS build produced in
|
||||||
|
# the node stage above — the final image never installs Node.
|
||||||
COPY src/frontend/flask_app/ ./flask_app/
|
COPY src/frontend/flask_app/ ./flask_app/
|
||||||
|
COPY --from=tailwind-build /app/flask_app/static/css/tailwind.css ./flask_app/static/css/tailwind.css
|
||||||
# Build TailwindCSS (one-shot; no watcher in production image).
|
|
||||||
#
|
|
||||||
# Versione esatta, non `tailwindcss@3`. Con il vincolo aperto ogni ricostruzione
|
|
||||||
# dell'immagine poteva prendere una minor diversa e produrre un CSS diverso senza
|
|
||||||
# che nessuno l'avesse validato: per un sistema che produce evidenze per audit
|
|
||||||
# ISO 9001 / IATF 16949 è lo stesso problema che il punto 12 risolve per le
|
|
||||||
# librerie del browser. Aggiornarla è una decisione, non un effetto collaterale.
|
|
||||||
WORKDIR /app/flask_app
|
|
||||||
RUN npm install tailwindcss@3.4.19 && \
|
|
||||||
npx tailwindcss -i static/css/input.css -o static/css/tailwind.css --minify
|
|
||||||
|
|
||||||
# Compile Flask-Babel translation catalogs.
|
# Compile Flask-Babel translation catalogs.
|
||||||
RUN uv run --project /app pybabel compile -d translations
|
WORKDIR /app/flask_app
|
||||||
|
RUN uv run --project /app pybabel compile -d translations && \
|
||||||
|
chown -R app:app /app
|
||||||
|
|
||||||
|
USER app
|
||||||
|
|
||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
|
|||||||
+9
-2
@@ -1,4 +1,4 @@
|
|||||||
FROM python:3.13-slim
|
FROM python:3.13.15-slim
|
||||||
|
|
||||||
# opencv-python (pulled in transitively by vs-core/vs-task/vs-measure/vs-pm2d)
|
# opencv-python (pulled in transitively by vs-core/vs-task/vs-measure/vs-pm2d)
|
||||||
# needs libGL and glib at runtime even though it is never imported by name here.
|
# needs libGL and glib at runtime even though it is never imported by name here.
|
||||||
@@ -6,7 +6,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
libgl1 libglib2.0-0 \
|
libgl1 libglib2.0-0 \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
|
COPY --from=ghcr.io/astral-sh/uv:0.10.9 /uv /usr/local/bin/uv
|
||||||
|
|
||||||
|
# Non-root user the app runs as at runtime. Same UID as the server's Dockerfile
|
||||||
|
# so both containers agree on ownership of the shared uploads volume (point 13).
|
||||||
|
RUN useradd -u 10001 app
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY pyproject.toml uv.lock ./
|
COPY pyproject.toml uv.lock ./
|
||||||
@@ -34,6 +38,9 @@ RUN test -n "$VISION_ENGINE_VERSION" || { \
|
|||||||
}
|
}
|
||||||
ENV VISION_ENGINE_VERSION=${VISION_ENGINE_VERSION}
|
ENV VISION_ENGINE_VERSION=${VISION_ENGINE_VERSION}
|
||||||
|
|
||||||
|
RUN chown -R app:app /app
|
||||||
|
USER app
|
||||||
|
|
||||||
EXPOSE 8100
|
EXPOSE 8100
|
||||||
|
|
||||||
# Two workers, not four: each holds the vision stack in memory.
|
# Two workers, not four: each holds the vision stack in memory.
|
||||||
|
|||||||
Reference in New Issue
Block a user