# Déploiement institutionnel — Picarones > Ce guide cible les **DSI de bibliothèques nationales et services > d'archives** qui souhaitent héberger Picarones sur leur propre > infrastructure (intranet, derrière SSO, avec stockage centralisé) > plutôt que sur HuggingFace Space public. > > Pour le déploiement HuggingFace Space ou un usage local rapide, > voir [`how-to/install.md`](../how-to/install.md). ## Pré-requis ### Système - **Linux x86_64 ou ARM64** (Debian 12+, RHEL 9+, Ubuntu 22.04+ LTS, Rocky 9+). - **Python 3.11 ou 3.12** (3.13 informationnel). - **Tesseract OCR ≥ 5.3** (avec packs `fra`, `lat`, `eng` au minimum). - **3 GB RAM** pour un worker FastAPI exécutant `max_in_flight=4` documents en parallèle dans le ThreadPool du `CorpusRunner` (profil mémoire dominé par Pillow + jiwer + les modèles OCR locaux chargés une fois par instance). - **5 GB de disque** pour l'application + 50 GB recommandés pour les uploads et la base SQLite des jobs. ### Réseau - **Sortant** : optionnel (HF Datasets / Gallica / HTR-United uniquement si vous activez les imports distants). - **Entrant** : un seul port HTTP (défaut 7860) à exposer derrière votre reverse proxy (Nginx, Apache, Traefik). ### Optionnel - **PostgreSQL 14+** (en remplacement de SQLite si vous montez en multi-instance — voir § Architecture cible). - **Reverse proxy SSO** (Shibboleth, CAS, OIDC, OAuth2 proxy). - **Stack observabilité** (Prometheus + Grafana, ou ELK/Loki). ## Architecture cible ### Mono-instance (recommandé pour < 10 utilisateurs simultanés) ``` [Utilisateur] → [Reverse proxy SSO] → [Picarones Docker] → [SQLite jobs.db] ↓ [Volume persistant uploads/] ↓ [Volume persistant reports/] ``` Configuration minimale, rétro-compatible avec le déploiement HuggingFace Space. Le reverse proxy ajoute l'authentification (SSO institutionnel) et la terminaison TLS. ### Multi-instance (charge > 50 jobs/h) ``` [Utilisateur] → [Load balancer + SSO] → [Picarones × N] ↓ [PostgreSQL jobs (centralisé)] ↓ [Volume NFS uploads/ partagé] ``` Notes : - **PostgreSQL** : `JobStore` utilise SQLite par défaut. Pour PostgreSQL, dériver une classe `PostgresJobStore` qui implémente la même API (`create_job`, `update_progress`, `get_job`, etc.). À défaut, partager la BD SQLite via NFS ne fonctionne pas — le mode WAL exige un filesystem local. - **Volume NFS** pour `uploads/` et `reports/` afin que tous les workers voient les mêmes fichiers. - **Sticky sessions** sur le LB pour SSE (les progress streams doivent rester sur le même worker). ## Configuration Toutes les variables sont documentées dans [`.env.example`](../../.env.example). Les principales pour un déploiement institutionnel : ```bash # Sécurité (Sprints A4 + 24) PICARONES_PUBLIC_MODE= # vide ou 0 = mode dev (autorise OCR cloud) PICARONES_CSRF_REQUIRED=1 # OBLIGATOIRE derrière SSO PICARONES_CSRF_SECRET="$(openssl rand -hex 32)" # Restrictions PICARONES_BROWSE_ROOTS="/var/lib/picarones/uploads:/data/corpus" PICARONES_MAX_UPLOAD_MB=500 PICARONES_MAX_CONCURRENT_JOBS=8 PICARONES_RATE_LIMIT_PER_HOUR=0 # 0 = illimité (le SSO gère l'identité) # Persistance PICARONES_JOBS_DB=/var/lib/picarones/jobs.sqlite # RGPD PICARONES_UPLOAD_RETENTION_DAYS=7 PICARONES_LOG_IP_RETENTION_HOURS=24 ``` ## Intégration SSO Picarones n'implémente **pas** de mécanisme d'authentification natif — l'authentification est déléguée à votre reverse proxy. Pattern recommandé : header trusté `X-Remote-User`. ### Nginx + Shibboleth (université, Renater) ```nginx location / { auth_request /shibauthorizer; proxy_set_header X-Remote-User $http_remote_user; proxy_set_header X-Remote-Groups $http_remote_groups; proxy_pass http://picarones-backend:7860; # SSE long-polling proxy_buffering off; proxy_read_timeout 24h; } ``` ### Apache + CAS (CRU, ESR français) ```apache AuthType CAS Require valid-user RequestHeader set X-Remote-User %{REMOTE_USER}s ProxyPass http://localhost:7860/ ProxyPassReverse http://localhost:7860/ ``` ### Traefik + OIDC (déploiements modernes) ```yaml http: middlewares: oidc-auth: forwardAuth: address: "http://oauth2-proxy:4180/auth" trustForwardHeader: true authResponseHeaders: - X-Auth-Request-User - X-Auth-Request-Email routers: picarones: rule: "Host(`picarones.institution.fr`)" service: picarones tls: certResolver: letsencrypt middlewares: - oidc-auth ``` ## Sauvegarde et restauration ### Composants à sauvegarder | Élément | Chemin | Stratégie | |---|---|---| | BD jobs | `/var/lib/picarones/jobs.sqlite*` | Snapshot quotidien (mode WAL : sauvegarder `.sqlite`, `.sqlite-wal`, `.sqlite-shm` ensemble) | | Uploads | `/var/lib/picarones/uploads/` | Snapshot hebdomadaire, rétention 30 jours (cf. RGPD) | | Rapports | `/var/lib/picarones/reports/` | Snapshot hebdomadaire, rétention illimitée (artefacts citables) | | Historique longitudinal | `/var/lib/picarones/history.sqlite` | Snapshot quotidien | | Configuration | `/etc/picarones/`, `.env` | Versionner dans le système de gestion de config (Ansible, Salt) | ### Restauration ```bash # Arrêt du service systemctl stop picarones # Restauration BD cp backups/jobs.sqlite-2026-05-01.sqlite /var/lib/picarones/jobs.sqlite # Restauration uploads rsync -av backups/uploads-2026-05-01/ /var/lib/picarones/uploads/ # Redémarrage systemctl start picarones # Vérification : marquage des jobs orphelins curl http://localhost:7860/api/status ``` Les jobs `running` au moment du snapshot sont automatiquement marqués `interrupted` au redémarrage. Le tableau de bord sera donc cohérent. ## Migration de schéma BD Picarones évolue sa BD via une stratégie **append-only** — nouvelles colonnes ajoutées avec `ALTER TABLE ADD COLUMN ... DEFAULT NULL`. Aucune migration destructive entre versions mineures. Pour vérifier la compatibilité d'une BD existante avec une nouvelle version : ```bash sqlite3 jobs.sqlite "PRAGMA table_info(jobs);" > current_schema.txt # Comparer avec docs/schema/jobs.sqlite.X.Y.Z.sql versionné ``` Si une migration majeure est nécessaire (changement de moteur SQL, structure incompatible), elle sera annoncée 2 versions mineures avant et un script de migration sera fourni dans `scripts/migrate/`. ## Observabilité ### Logs structurés Picarones logge en **format texte simple** par défaut. Pour ELK / Loki / Datadog, ajouter un wrapper JSON : ```python # /etc/picarones/logging.conf [handler_json] class = pythonjsonlogger.jsonlogger.JsonFormatter format = %(asctime)s %(levelname)s %(name)s %(message)s ``` Variable d'env : `PICARONES_LOG_FORMAT=json` (à implémenter dans un sprint ultérieur — actuellement les logs sont en plain text). ### Métriques Prometheus (recommandé) L'exposition Prometheus n'est pas livrée par défaut. Pour l'ajouter, monter un conteneur sidecar `prometheus_client_python` qui expose : - `picarones_jobs_total{status="..."}` - `picarones_jobs_duration_seconds` - `picarones_uploads_size_bytes_total` - `picarones_engine_invocations_total{engine="..."}` Voir `docs/operations/observability.md`. ### Healthcheck Un endpoint `/health` minimal répond en < 50 ms sans toucher à la BD ni aux engines. Configurer le LB pour le cibler avec un timeout court (5 s). ## Sécurité réseau ### Liste blanche réseau Si vos engines cloud sont activés (`PICARONES_PUBLIC_MODE` non défini), autoriser en sortie uniquement : | Domaine | Usage | |---|---| | `api.openai.com` | OpenAI / GPT-4o | | `api.anthropic.com` | Claude | | `api.mistral.ai` | Mistral OCR + LLM | | `vision.googleapis.com` | Google Vision | | `*.cognitiveservices.azure.com` | Azure Doc Intelligence | | `huggingface.co` | Imports HF Datasets (optionnel) | | `gallica.bnf.fr` | Imports Gallica (optionnel) | ### Politique de mots de passe Les clés API LLM/OCR sont passées **en variables d'environnement uniquement** (jamais sur le filesystem en clair). Voir [`SECURITY.md`](../../SECURITY.md). ## Mise à l'échelle | Charge | Configuration | |---|---| | < 5 jobs/h, < 5 utilisateurs | Mono-instance, SQLite, 2 vCPU / 4 GB RAM | | 5–50 jobs/h, < 20 utilisateurs | Mono-instance, SQLite, 4 vCPU / 8 GB RAM, `max_in_flight=8` | | > 50 jobs/h | Multi-instance derrière LB, PostgreSQL centralisé, NFS uploads | | > 500 jobs/h | Considérer un orchestrateur de tâches dédié (Celery + Redis), hors scope Picarones | ## Checklist déploiement - [ ] Tesseract installé avec packs de langues nécessaires. - [ ] Variables d'env configurées (mode dev/public, CSRF, browse roots). - [ ] Volume persistant pour `uploads/`, `reports/`, BD. - [ ] Reverse proxy SSO en place (CSRF activé !). - [ ] Backup automatique configuré (cron quotidien minimum). - [ ] Healthcheck `/health` configuré dans le LB. - [ ] TLS terminé au reverse proxy. - [ ] Liste blanche réseau si engines cloud actifs. - [ ] Rétention RGPD configurée (cf. [`data-retention-rgpd.md`](data-retention-rgpd.md)). - [ ] Audit RGAA externe planifié si prestation publique (cf. [`accessibility.md`](accessibility.md)). - [ ] Issue tracking institutionnel (Mantis, JIRA, Redmine) synchronisé avec les issues GitHub si pertinent. ## Aide et support - Issues GitHub étiquetées `deployment` : - Pour un support contractualisé (SLO renforcés, intégration spécifique), contractualiser une prestation séparément (modalités hors-projet, à définir au cas par cas). --- *Dernière mise à jour : 2 mai 2026.*