File size: 9,033 Bytes
bff1348
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fc30527
df7146b
 
 
fc30527
df7146b
 
 
 
 
fc30527
df7146b
fc30527
df7146b
 
 
 
 
 
 
 
fc30527
df7146b
 
 
 
fc30527
df7146b
fc30527
 
bff1348
 
 
657a5ae
 
 
 
 
 
 
 
 
 
bff1348
df7146b
 
 
bff1348
 
df7146b
bff1348
 
4223748
 
 
 
 
 
df7146b
 
 
 
 
 
 
 
4223748
 
df7146b
 
bff1348
 
4223748
 
 
657a5ae
 
 
bff1348
 
 
fc30527
 
df7146b
 
 
fc30527
bff1348
 
 
cecde1f
bff1348
 
 
 
 
657a5ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bff1348
 
 
 
 
 
 
 
 
 
 
 
 
e224609
bff1348
 
 
 
 
 
 
 
a25f0d4
bff1348
 
 
a25f0d4
bff1348
 
a25f0d4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# 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"]