Backend: rate limiter, security headers, blockchain cache service avec RPC, public API (7 endpoints read-only), WebSocket auth + heartbeat, DB connection pooling, structured logging, health check DB. Frontend: API retry/timeout, WebSocket auth + heartbeat + typed events, notifications toast, mobile hamburger + drawer, error boundary, offline banner, loading skeletons, dashboard enrichi. Documentation: guides utilisateur complets (demarrage, vote, sanctuaire, FAQ 30+), guide deploiement, politique securite. 123 tests, 155 fichiers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
406 lines
13 KiB
Markdown
406 lines
13 KiB
Markdown
---
|
|
title: Deploiement
|
|
description: Guide de deploiement en production de Glibredecision
|
|
---
|
|
|
|
# Deploiement
|
|
|
|
Ce guide couvre le deploiement complet de Glibredecision en production avec Docker, Traefik, PostgreSQL et IPFS.
|
|
|
|
## Prerequis
|
|
|
|
| Composant | Version minimale | Description |
|
|
| --------- | ---------------- | ----------- |
|
|
| Docker | 24+ | Moteur de conteneurs |
|
|
| Docker Compose | 2.20+ | Orchestration multi-conteneurs |
|
|
| Nom de domaine | -- | Domaine pointe vers le serveur (ex: `glibredecision.org`) |
|
|
| Certificat TLS | -- | Genere automatiquement par Traefik via Let's Encrypt |
|
|
| Traefik | 2.10+ | Reverse proxy avec terminaison TLS (reseau externe `traefik`) |
|
|
| Serveur | 2 vCPU, 4 Go RAM, 40 Go SSD | Ressources recommandees |
|
|
|
|
### Reseau Traefik
|
|
|
|
Le deploiement suppose qu'un reseau Docker externe `traefik` existe deja avec une instance Traefik configuree. Si ce n'est pas le cas, creez-le :
|
|
|
|
```bash
|
|
docker network create traefik
|
|
```
|
|
|
|
Et deployez Traefik separement (voir section [Configuration Traefik](#configuration-traefik)).
|
|
|
|
## Configuration .env
|
|
|
|
Copiez le fichier `.env.example` et configurez chaque variable pour la production :
|
|
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
### Variables d'environnement
|
|
|
|
| Variable | Description | Valeur par defaut | Production |
|
|
| -------- | ----------- | ----------------- | ---------- |
|
|
| `POSTGRES_DB` | Nom de la base de donnees | `glibredecision` | `glibredecision` |
|
|
| `POSTGRES_USER` | Utilisateur PostgreSQL | `glibredecision` | `glibredecision` |
|
|
| `POSTGRES_PASSWORD` | Mot de passe PostgreSQL | `change-me-in-production` | **Generer un mot de passe fort** (32+ caracteres) |
|
|
| `DATABASE_URL` | URL de connexion asyncpg | `postgresql+asyncpg://...@localhost:5432/...` | Construite automatiquement dans docker-compose |
|
|
| `SECRET_KEY` | Cle secrete pour les tokens de session | `change-me-in-production-with-a-real-secret-key` | **Generer une cle aleatoire** (`openssl rand -hex 64`) |
|
|
| `DEBUG` | Mode debug | `true` | **`false`** |
|
|
| `CORS_ORIGINS` | Origines CORS autorisees | `["http://localhost:3002"]` | `["https://glibredecision.org"]` |
|
|
| `DUNITER_RPC_URL` | URL du noeud Duniter V2 RPC | `wss://gdev.p2p.legal/ws` | URL du noeud de production |
|
|
| `IPFS_API_URL` | URL de l'API IPFS (kubo) | `http://localhost:5001` | `http://ipfs:5001` (interne Docker) |
|
|
| `IPFS_GATEWAY_URL` | URL de la passerelle IPFS | `http://localhost:8080` | `http://ipfs:8080` (interne Docker) |
|
|
| `NUXT_PUBLIC_API_BASE` | URL publique de l'API pour le frontend | `http://localhost:8002/api/v1` | `https://glibredecision.org/api/v1` |
|
|
| `DOMAIN` | Nom de domaine | `glibredecision.org` | Votre domaine |
|
|
|
|
### Generer les secrets
|
|
|
|
```bash
|
|
# Generer POSTGRES_PASSWORD
|
|
openssl rand -hex 32
|
|
|
|
# Generer SECRET_KEY
|
|
openssl rand -hex 64
|
|
```
|
|
|
|
::callout{type="warning"}
|
|
Ne commitez jamais le fichier `.env` contenant les secrets de production. Ajoutez-le au `.gitignore`.
|
|
::
|
|
|
|
## Lancement avec docker-compose
|
|
|
|
### Premier deploiement
|
|
|
|
```bash
|
|
# Se placer dans le repertoire du projet
|
|
cd /opt/glibredecision
|
|
|
|
# Cloner le depot
|
|
git clone https://git.duniter.org/tools/glibredecision.git .
|
|
|
|
# Configurer l'environnement
|
|
cp .env.example .env
|
|
# Editer .env avec les valeurs de production
|
|
|
|
# Construire et demarrer les services
|
|
docker compose -f docker/docker-compose.yml up -d --build
|
|
|
|
# Verifier que tous les services sont sains
|
|
docker compose -f docker/docker-compose.yml ps
|
|
```
|
|
|
|
### Services deployes
|
|
|
|
| Service | Description | Port interne | Expose |
|
|
| ------- | ----------- | ------------ | ------ |
|
|
| `postgres` | Base de donnees PostgreSQL 16 | 5432 | Non (interne uniquement) |
|
|
| `backend` | API FastAPI | 8002 | Via Traefik (`/api/*`) |
|
|
| `frontend` | Application Nuxt 4 | 3000 | Via Traefik (racine) |
|
|
| `ipfs` | Noeud IPFS kubo | 5001, 8080 | Non (interne uniquement) |
|
|
|
|
### Verifier le deploiement
|
|
|
|
```bash
|
|
# Statut des conteneurs
|
|
docker compose -f docker/docker-compose.yml ps
|
|
|
|
# Logs d'un service specifique
|
|
docker compose -f docker/docker-compose.yml logs -f backend
|
|
|
|
# Health check de l'API
|
|
curl -s https://glibredecision.org/api/health | jq .
|
|
```
|
|
|
|
## Migration de base de donnees (Alembic)
|
|
|
|
Glibredecision utilise Alembic pour les migrations de schema PostgreSQL.
|
|
|
|
### Appliquer les migrations
|
|
|
|
```bash
|
|
# Executer les migrations dans le conteneur backend
|
|
docker compose -f docker/docker-compose.yml exec backend alembic upgrade head
|
|
```
|
|
|
|
### Verifier l'etat des migrations
|
|
|
|
```bash
|
|
docker compose -f docker/docker-compose.yml exec backend alembic current
|
|
```
|
|
|
|
### Creer une nouvelle migration
|
|
|
|
```bash
|
|
# En developpement uniquement
|
|
docker compose -f docker/docker-compose.yml exec backend alembic revision --autogenerate -m "description de la migration"
|
|
```
|
|
|
|
### Rollback d'une migration
|
|
|
|
```bash
|
|
# Revenir d'une migration
|
|
docker compose -f docker/docker-compose.yml exec backend alembic downgrade -1
|
|
```
|
|
|
|
## Seed des donnees initiales
|
|
|
|
Apres la premiere migration, vous pouvez charger les donnees de seed (documents de reference initiaux) :
|
|
|
|
```bash
|
|
# Executer le script de seed dans le conteneur backend
|
|
docker compose -f docker/docker-compose.yml exec backend python -m app.seed
|
|
```
|
|
|
|
Les donnees de seed incluent :
|
|
|
|
- La Licence G1 avec ses items
|
|
- L'Engagement Forgeron v2.0.0
|
|
- L'Engagement Comite Technique v2.0.0
|
|
- Le template de processus de Runtime Upgrade
|
|
- Les protocoles de vote par defaut avec leurs formules
|
|
|
|
## Configuration Traefik
|
|
|
|
### Configuration minimale Traefik
|
|
|
|
Si vous n'avez pas encore Traefik, voici une configuration minimale. Creez un fichier `docker-compose.traefik.yml` :
|
|
|
|
```yaml
|
|
version: "3.9"
|
|
|
|
services:
|
|
traefik:
|
|
image: traefik:v2.10
|
|
restart: unless-stopped
|
|
command:
|
|
- "--api.dashboard=false"
|
|
- "--providers.docker=true"
|
|
- "--providers.docker.exposedbydefault=false"
|
|
- "--providers.docker.network=traefik"
|
|
- "--entrypoints.web.address=:80"
|
|
- "--entrypoints.websecure.address=:443"
|
|
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
|
|
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
|
- "--certificatesresolvers.letsencrypt.acme.tlschallenge=true"
|
|
- "--certificatesresolvers.letsencrypt.acme.email=admin@glibredecision.org"
|
|
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
|
|
ports:
|
|
- "80:80"
|
|
- "443:443"
|
|
volumes:
|
|
- "/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
- "letsencrypt:/letsencrypt"
|
|
networks:
|
|
- traefik
|
|
|
|
volumes:
|
|
letsencrypt:
|
|
|
|
networks:
|
|
traefik:
|
|
external: true
|
|
```
|
|
|
|
```bash
|
|
docker compose -f docker-compose.traefik.yml up -d
|
|
```
|
|
|
|
### Routage
|
|
|
|
Le `docker-compose.yml` de Glibredecision configure automatiquement les labels Traefik :
|
|
|
|
- **Frontend** : `Host(glibredecision.org)` sur le port 3000
|
|
- **Backend** : `Host(glibredecision.org) && PathPrefix(/api)` sur le port 8002
|
|
- Les deux utilisent le certificat Let's Encrypt (`certresolver=letsencrypt`)
|
|
- Redirection HTTP vers HTTPS automatique
|
|
|
|
### Certificat TLS
|
|
|
|
Le certificat est genere automatiquement par Traefik via Let's Encrypt (challenge TLS-ALPN-01). Assurez-vous que :
|
|
|
|
1. Le domaine pointe vers l'adresse IP du serveur (enregistrement DNS A)
|
|
2. Les ports 80 et 443 sont ouverts dans le firewall
|
|
3. L'adresse email dans la configuration Traefik est valide
|
|
|
|
## Monitoring
|
|
|
|
### Health checks
|
|
|
|
Le service PostgreSQL dispose d'un health check integre (`pg_isready`). Le backend expose un endpoint de sante :
|
|
|
|
```bash
|
|
# Health check de l'API
|
|
curl -s https://glibredecision.org/api/health
|
|
# Reponse attendue : {"status": "healthy"}
|
|
```
|
|
|
|
### Logs
|
|
|
|
```bash
|
|
# Suivre les logs de tous les services
|
|
docker compose -f docker/docker-compose.yml logs -f
|
|
|
|
# Logs d'un service specifique
|
|
docker compose -f docker/docker-compose.yml logs -f backend
|
|
docker compose -f docker/docker-compose.yml logs -f frontend
|
|
docker compose -f docker/docker-compose.yml logs -f postgres
|
|
|
|
# Derniers 100 lignes
|
|
docker compose -f docker/docker-compose.yml logs --tail=100 backend
|
|
```
|
|
|
|
### Metriques
|
|
|
|
Surveillez les indicateurs suivants :
|
|
|
|
| Indicateur | Commande | Seuil d'alerte |
|
|
| ---------- | -------- | --------------- |
|
|
| CPU/RAM conteneurs | `docker stats` | > 80% RAM |
|
|
| Espace disque | `df -h` | > 85% |
|
|
| Connexions PostgreSQL | `docker exec postgres psql -U glibredecision -c "SELECT count(*) FROM pg_stat_activity;"` | > 80 |
|
|
| Taille base de donnees | `docker exec postgres psql -U glibredecision -c "SELECT pg_size_pretty(pg_database_size('glibredecision'));"` | Information |
|
|
| Statut IPFS | `docker exec ipfs ipfs id` | Erreur |
|
|
|
|
## Sauvegarde PostgreSQL
|
|
|
|
### Sauvegarde manuelle
|
|
|
|
```bash
|
|
# Dump complet de la base
|
|
docker compose -f docker/docker-compose.yml exec postgres \
|
|
pg_dump -U glibredecision -Fc glibredecision > backup_$(date +%Y%m%d_%H%M%S).dump
|
|
```
|
|
|
|
### Restauration
|
|
|
|
```bash
|
|
# Restaurer un dump
|
|
docker compose -f docker/docker-compose.yml exec -T postgres \
|
|
pg_restore -U glibredecision -d glibredecision --clean < backup_20260228_120000.dump
|
|
```
|
|
|
|
### Sauvegarde automatique (cron)
|
|
|
|
Ajoutez un crontab pour des sauvegardes quotidiennes :
|
|
|
|
```bash
|
|
# Editer le crontab
|
|
crontab -e
|
|
|
|
# Ajouter une sauvegarde quotidienne a 3h du matin
|
|
0 3 * * * cd /opt/glibredecision && docker compose -f docker/docker-compose.yml exec -T postgres pg_dump -U glibredecision -Fc glibredecision > /opt/backups/glibredecision_$(date +\%Y\%m\%d).dump && find /opt/backups -name "glibredecision_*.dump" -mtime +30 -delete
|
|
```
|
|
|
|
Cette commande :
|
|
1. Execute un dump quotidien a 3h du matin
|
|
2. Stocke les sauvegardes dans `/opt/backups/`
|
|
3. Supprime automatiquement les sauvegardes de plus de 30 jours
|
|
|
|
## Mise a jour
|
|
|
|
### Procedure standard
|
|
|
|
```bash
|
|
cd /opt/glibredecision
|
|
|
|
# 1. Tirer les dernieres images
|
|
docker compose -f docker/docker-compose.yml pull
|
|
|
|
# 2. Redemarrer les services avec les nouvelles images
|
|
docker compose -f docker/docker-compose.yml up -d --remove-orphans
|
|
|
|
# 3. Appliquer les migrations de base de donnees
|
|
docker compose -f docker/docker-compose.yml exec backend alembic upgrade head
|
|
|
|
# 4. Nettoyer les anciennes images
|
|
docker image prune -f
|
|
|
|
# 5. Verifier le deploiement
|
|
docker compose -f docker/docker-compose.yml ps
|
|
curl -s https://glibredecision.org/api/health
|
|
```
|
|
|
|
### Pipeline CI/CD (Woodpecker)
|
|
|
|
La pipeline Woodpecker CI automatise le deploiement lors d'un push sur `main` :
|
|
|
|
1. **test-backend** : execution des tests Python (`pytest`)
|
|
2. **test-frontend** : build du frontend Nuxt (`npm run build`)
|
|
3. **docker-backend** : construction et push de l'image Docker backend
|
|
4. **docker-frontend** : construction et push de l'image Docker frontend
|
|
5. **deploy** : connexion SSH au serveur, pull des nouvelles images, redemarrage
|
|
|
|
Les secrets CI sont configures dans l'interface Woodpecker :
|
|
|
|
| Secret | Description |
|
|
| ------ | ----------- |
|
|
| `docker_registry` | URL du registre Docker |
|
|
| `docker_username` | Identifiant du registre |
|
|
| `docker_password` | Mot de passe du registre |
|
|
| `deploy_host` | Adresse du serveur de production |
|
|
| `deploy_username` | Utilisateur SSH |
|
|
| `deploy_key` | Cle privee SSH |
|
|
|
|
## Troubleshooting
|
|
|
|
### Le backend ne demarre pas
|
|
|
|
**Symptome** : Le conteneur backend redemoarre en boucle.
|
|
|
|
```bash
|
|
# Verifier les logs
|
|
docker compose -f docker/docker-compose.yml logs backend
|
|
|
|
# Causes courantes :
|
|
# 1. DATABASE_URL incorrecte -> verifier .env
|
|
# 2. PostgreSQL pas encore pret -> verifier le health check
|
|
# 3. Migrations non appliquees -> executer alembic upgrade head
|
|
```
|
|
|
|
### Erreur de connexion a PostgreSQL
|
|
|
|
**Symptome** : `connection refused` ou `password authentication failed`.
|
|
|
|
```bash
|
|
# Verifier que PostgreSQL est sain
|
|
docker compose -f docker/docker-compose.yml exec postgres pg_isready
|
|
|
|
# Verifier les variables d'environnement
|
|
docker compose -f docker/docker-compose.yml exec backend env | grep DATABASE
|
|
|
|
# Reinitialiser le mot de passe si necessaire (attention : destructif)
|
|
docker compose -f docker/docker-compose.yml down -v # supprime les volumes
|
|
docker compose -f docker/docker-compose.yml up -d # recree avec le nouveau mot de passe
|
|
```
|
|
|
|
### Certificat TLS non genere
|
|
|
|
**Symptome** : Le site est inaccessible en HTTPS ou affiche un certificat invalide.
|
|
|
|
1. Verifier que le DNS A/AAAA pointe vers le serveur : `dig glibredecision.org`
|
|
2. Verifier que les ports 80 et 443 sont ouverts : `ss -tlnp | grep -E '80|443'`
|
|
3. Consulter les logs Traefik : `docker logs traefik 2>&1 | grep -i acme`
|
|
|
|
### IPFS ne repond pas
|
|
|
|
**Symptome** : Erreur lors de l'archivage dans le Sanctuaire.
|
|
|
|
```bash
|
|
# Verifier le statut du noeud IPFS
|
|
docker compose -f docker/docker-compose.yml exec ipfs ipfs id
|
|
|
|
# Verifier l'espace disque disponible
|
|
docker compose -f docker/docker-compose.yml exec ipfs df -h /data/ipfs
|
|
|
|
# Redemarrer le noeud IPFS
|
|
docker compose -f docker/docker-compose.yml restart ipfs
|
|
```
|
|
|
|
### Erreur WebSocket
|
|
|
|
**Symptome** : L'indicateur de connexion temps reel est rouge.
|
|
|
|
1. Verifier que Traefik supporte les WebSockets (actif par defaut)
|
|
2. Verifier le routage : le WebSocket est sur `/api/v1/ws`
|
|
3. Verifier les logs backend pour les erreurs de connexion WebSocket
|