Spaces:
Sleeping
Sleeping
File size: 10,170 Bytes
95cbd83 | 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 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | # Déploiement institutionnel — Picarones
> Sprint A11 du plan de remédiation institutionnelle (item M-7).
>
> 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 [`INSTALL.md`](../../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 — Sprint A1).
- **Tesseract OCR ≥ 5.3** (avec packs `fra`, `lat`, `eng` au
minimum).
- **3 GB RAM par worker** (le ProcessPool spawne un sous-processus
par moteur ; profil mémoire dominé par Pillow + jiwer).
- **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` (Sprint 25) 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 (Sprint A11)
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
<Location />
AuthType CAS
Require valid-user
RequestHeader set X-Remote-User %{REMOTE_USER}s
ProxyPass http://localhost:7860/
ProxyPassReverse http://localhost:7860/
</Location>
```
### 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 (Sprint 26). 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` (à venir Sprint A11+).
### Healthcheck
Un endpoint `/health` minimal (Sprint A4 / M-3) 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, ProcessPool 8 workers |
| > 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` :
<https://github.com/maribakulj/Picarones/issues?q=label%3Adeployment>
- 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 (Sprint A11).*
|