# Dockerfile.prod — image immuable pour la stack prod EPTM Dashboard. # # Multi-stage : # 1. builder : installe deps Python + Node, exporte le frontend Reflex. # 2. runtime : Python slim, sans Node, sans cache npm, prêt à servir. # # Build : docker compose -f docker-compose.prod.yml build app # ───────────────────────────────────────────────────────────────────────────── # Stage 1 — builder FROM python:3.13 AS builder WORKDIR /app # Outils nécessaires au bundle frontend (Node + npm sont requis par `reflex export`). RUN apt-get update && apt-get install -y --no-install-recommends \ curl gnupg unzip xvfb ca-certificates && \ curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \ apt-get install -y nodejs && \ rm -rf /var/lib/apt/lists/* # Dépendances Python (installées dans le user-site pour pouvoir les copier # proprement dans le stage 2 — évite de réinstaller pip dans le runtime). COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt && \ pip install --no-cache-dir \ pdfplumber sqlalchemy plotly pandas openpyxl bcrypt pyyaml pypdf \ pyotp "qrcode[pil]" reportlab playwright markdown # Playwright : navigateur installé en system-wide pour le stage 2. RUN playwright install --with-deps chromium # Code applicatif + assets statiques + docs + templates AcroForm. COPY . . # `reflex init` prépare la conf locale (.web/, alembic, etc.). # `reflex export --frontend-only --no-zip` génère le bundle Vite statique # dans .web/build/ — c'est ce que servira le backend en prod. RUN reflex init && \ reflex export --frontend-only --no-zip # ───────────────────────────────────────────────────────────────────────────── # Stage 2 — runtime FROM python:3.13 WORKDIR /app # Runtime allégé : Node n'est PAS réinstallé (`reflex export` a déjà créé le # bundle). On garde curl pour les healthchecks et ca-certificates pour SMTP/HTTPS. RUN apt-get update && apt-get install -y --no-install-recommends \ curl ca-certificates tzdata && \ rm -rf /var/lib/apt/lists/* # Copie les Python deps installées dans le builder. COPY --from=builder /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages COPY --from=builder /usr/local/bin /usr/local/bin # Playwright browsers (cache global déjà téléchargé dans le builder). COPY --from=builder /root/.cache/ms-playwright /root/.cache/ms-playwright # Libs système requises par Chromium headless (libnspr4, libnss3, fonts, etc.). # Sans ça, le binaire chromium-headless-shell ne charge pas et la sync Escada # meurt avec "error while loading shared libraries: libnspr4.so". RUN apt-get update && \ playwright install-deps chromium && \ rm -rf /var/lib/apt/lists/* # Copie l'app entièrement déjà bundlée (avec .web/ + reflex.json + etc.). COPY --from=builder /app /app # Reflex 0.9+ exige un seul port en prod (frontend statique + backend granian). # 3002 choisi pour cohabiter avec dev (3001 frontend Vite + 8001 backend). ENV FRONTEND_PORT=3002 BACKEND_PORT=3002 \ TZ=Europe/Zurich \ PYTHONUNBUFFERED=1 EXPOSE 3002 # `reflex run --env prod` lance backend granian + sert le frontend depuis .web/build. CMD ["reflex", "run", "--env", "prod"]