Picarones / Dockerfile
Claude
feat(sprint-A16): build Docker reproductible (digest + lock file) β€” clΓ΄ture M-2
df7146b unverified
Raw
History Blame
9.03 kB
# Dockerfile β€” Picarones
# Image Docker multi-Γ©tape avec Tesseract OCR prΓ©-installΓ©
#
# Usage :
# docker build -t picarones:latest .
# docker run -p 8000:8000 picarones:latest
# docker run -p 8000:8000 -v $(pwd)/corpus:/app/corpus picarones:latest
#
# Variables d'environnement supportΓ©es :
# OPENAI_API_KEY, ANTHROPIC_API_KEY, MISTRAL_API_KEY
# GOOGLE_APPLICATION_CREDENTIALS
# AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_DEFAULT_REGION
# AZURE_DOC_INTEL_ENDPOINT, AZURE_DOC_INTEL_KEY
# ──────────────────────────────────────────────────────────────────
# Γ‰tape 1 : builder β€” installe les dΓ©pendances Python dans un venv
# ──────────────────────────────────────────────────────────────────
# ──────────────────────────────────────────────────────────────────
# Sprint A8 (M-2) + Sprint A16 (build dΓ©terministe) β€” image de base
# Γ©pinglΓ©e Γ  la fois par tag (lisibilitΓ© humaine) et par digest sha256
# (reproductibilitΓ© bit-Γ -bit).
#
# Pourquoi le digest : ``python:3.11.13-slim`` peut Γͺtre re-publiΓ© au
# fil des patches Debian avec un mΓͺme tag mais un contenu diffΓ©rent.
# Pour la reproductibilitΓ© institutionnelle BnF, ``@sha256:...`` fige
# l'image binaire β€” deux ``docker build`` sΓ©parΓ©s produisent une
# couche de base identique octet par octet.
#
# Rotation trimestrielle (avant chaque release majeure) :
#
# TOKEN=$(curl -s "https://auth.docker.io/token?\
# service=registry.docker.io&scope=repository:library/python:pull" \
# | jq -r .token)
# curl -sI -H "Authorization: Bearer $TOKEN" \
# -H "Accept: application/vnd.oci.image.index.v1+json" \
# https://registry-1.docker.io/v2/library/python/manifests/3.11.13-slim \
# | grep -i docker-content-digest
# # β†’ mettre Γ  jour le digest ci-dessous + bumper PYTHON_BASE_IMAGE
#
# La forme ``image:tag@sha256:...`` est documentΓ©e par Docker comme
# valide ; les machines de dΓ©veloppement sans registry proxy peuvent
# pull aussi bien que par tag β€” le digest Γ©tant immuable, le pull
# est strictement Γ©quivalent Γ  un pull par tag actuel.
# ──────────────────────────────────────────────────────────────────
ARG PYTHON_BASE_IMAGE=python:3.11.13-slim@sha256:9bffe4353b925a1656688797ebc68f9c525e79b1d377a764d232182a519eeec4
FROM ${PYTHON_BASE_IMAGE} AS builder
WORKDIR /app
# Sprint A14 (correctif suite scan Trivy CI) β€” applique en prioritΓ© les
# patches Debian disponibles AVANT d'installer build-essential/git, pour
# Γ©viter d'embarquer les CVE de la base image (libssl3t64, libc6, etc.).
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
build-essential \
git && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Copier les fichiers de configuration du package + lock file Docker.
# ``requirements-docker.lock`` (Sprint A16) gèle l'arbre de dépendances
# transitif rΓ©solu par ``uv pip compile pyproject.toml --extra web --extra llm``.
COPY pyproject.toml .
COPY README.md .
COPY requirements-docker.lock .
COPY picarones/ picarones/
# CrΓ©e le venv isolΓ© /opt/venv et l'active pour les ``RUN`` suivants.
# Le runtime fera ``COPY --from=builder /opt/venv /opt/venv`` ; sans cette
# crΓ©ation explicite le COPY Γ©choue (rΓ©gression remontΓ©e par CI A14).
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Sprint A16 : installation dΓ©terministe via lock file.
#
# 1. Patch pip/setuptools/wheel (Trivy scanne /opt/venv/lib/python3.11/
# site-packages β€” sans patch les CVE setuptools/wheel ressortent).
# 2. ``--no-deps`` sur le lock empΓͺche pip de re-rΓ©soudre β€” l'arbre
# pinnΓ© par ``uv pip compile`` est complet, transitives incluses.
# 3. ``--no-deps`` sur picarones lui-mΓͺme : le lock contient dΓ©jΓ 
# toutes ses dΓ©pendances ; cette ligne installe juste le code.
RUN pip install --upgrade --no-cache-dir \
"pip>=24.2" "setuptools>=78.1.1" "wheel>=0.46.2" && \
pip install --no-cache-dir --no-deps -r requirements-docker.lock && \
pip install --no-cache-dir --no-deps -e . && \
pip cache purge
# Patch également la copie système de pip/setuptools/wheel (hors venv)
# que Trivy dΓ©tecte via ``/usr/local/lib/python3.11/site-packages`` β€”
# subsiste dans l'image runtime mΓͺme quand le venv est utilisΓ©.
RUN /usr/local/bin/pip install --upgrade --no-cache-dir \
"pip>=24.2" "setuptools>=78.1.1" "wheel>=0.46.2"
# ──────────────────────────────────────────────────────────────────
# Étape 2 : runtime — image finale légère avec Tesseract
# ──────────────────────────────────────────────────────────────────
# ARG redΓ©clarΓ© ici car les variables ARG hors ``FROM`` sont scopΓ©es
# par Γ©tape ; sans cette redΓ©claration le ``FROM`` du runtime perd
# l'Γ©pinglage du builder. La valeur DOIT correspondre Γ  celle de
# l'Γ©tape builder (digest inclus) β€” sinon les couches OS divergent.
ARG PYTHON_BASE_IMAGE=python:3.11.13-slim@sha256:9bffe4353b925a1656688797ebc68f9c525e79b1d377a764d232182a519eeec4
FROM ${PYTHON_BASE_IMAGE} AS runtime
LABEL description="Picarones β€” Plateforme de comparaison de moteurs OCR pour documents patrimoniaux"
LABEL version="1.0.0"
LABEL org.opencontainers.image.source="https://github.com/maribakulj/Picarones"
LABEL org.opencontainers.image.licenses="Apache-2.0"
WORKDIR /app
# ── DΓ©pendances systΓ¨me ─────────────────────────────────────────
# Sprint A14 (correctif Trivy) : ``apt-get upgrade -y`` avant install
# pour rΓ©cupΓ©rer les patches de sΓ©curitΓ© Debian (libssl3t64, libc6,
# openssl, etc.) β€” la base image Python ne les inclut pas par dΓ©faut.
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
# Tesseract OCR 5 et modèles de langues
tesseract-ocr \
tesseract-ocr-fra \
tesseract-ocr-lat \
tesseract-ocr-eng \
tesseract-ocr-deu \
tesseract-ocr-ita \
tesseract-ocr-spa \
# Bibliothèques image pour Pillow
libpng16-16 \
libjpeg62-turbo \
libtiff6 \
libwebp7 \
# Utilitaires
curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Patch pip/setuptools/wheel système du runtime (en dehors du venv).
# Trivy scanne /usr/local/lib/python3.11/site-packages indΓ©pendamment.
RUN /usr/local/bin/pip install --upgrade --no-cache-dir \
"pip>=24.2" "setuptools>=78.1.1" "wheel>=0.46.2"
# ── Venv Python depuis le builder ──────────────────────────────
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# ── Code source de l'application ───────────────────────────────
COPY --from=builder /app /app
# ── RΓ©pertoires de donnΓ©es ──────────────────────────────────────
RUN mkdir -p /app/corpus /app/rapports /app/data
# ── Utilisateur non-root pour la sΓ©curitΓ© ──────────────────────
RUN useradd -m -u 1000 picarones && \
chown -R picarones:picarones /app /opt/venv
USER picarones
# ── Variables d'environnement par dΓ©faut ───────────────────────
ENV PYTHONUNBUFFERED=1
ENV PYTHONIOENCODING=utf-8
ENV TESSDATA_PREFIX=/usr/share/tesseract-ocr/5/tessdata
# ── Ports ───────────────────────────────────────────────────────
EXPOSE 7860
# ── Health check ────────────────────────────────────────────────
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
CMD curl -f http://localhost:7860/health || exit 1
# ── DΓ©marrage ───────────────────────────────────────────────────
CMD ["picarones", "serve", "--host", "0.0.0.0", "--port", "7860"]