| # Guide de Déploiement |
|
|
| ## Table des matières |
|
|
| 1. [Développement](#développement) |
| 2. [Production Local](#production-local) |
| 3. [Docker](#docker) |
| 4. [Cloud Providers](#cloud-providers) |
| 5. [Monitoring](#monitoring) |
| 6. [Sécurité](#sécurité) |
|
|
| ## Développement |
|
|
| ### Configuration |
|
|
| ```bash |
| # Créer environnement virtuel |
| python -m venv venv |
| source venv/bin/activate |
| |
| # Installer dépendances |
| pip install -r requirements.txt |
| |
| # Créer .env |
| cp .env.example .env |
| # Éditer .env avec vos clés API |
| ``` |
|
|
| ### Lancement |
|
|
| ```bash |
| # Mode développement avec rechargement automatique |
| python app.py |
| |
| # ou avec uvicorn directement |
| uvicorn app:app --reload --port 7860 |
| ``` |
|
|
| ## Production Local |
|
|
| ### Optimisations |
|
|
| ```bash |
| # Générer un secret JWT sécurisé |
| python -c "import secrets; print(secrets.token_urlsafe(32))" |
| |
| # Mettre à jour .env |
| ENVIRONMENT=production |
| JWT_SECRET_KEY=<secret-généré> |
| ``` |
|
|
| ### Lancement Production |
|
|
| ```bash |
| # Avec workers multiples pour performance |
| uvicorn app:app \ |
| --host 0.0.0.0 \ |
| --port 7860 \ |
| --workers 4 \ |
| --log-level info \ |
| --no-access-log |
| ``` |
|
|
| ### Avec Gunicorn (recommandé) |
|
|
| ```bash |
| # Installer gunicorn |
| pip install gunicorn |
| |
| # Lancer |
| gunicorn app:app \ |
| --workers 4 \ |
| --worker-class uvicorn.workers.UvicornWorker \ |
| --bind 0.0.0.0:7860 \ |
| --timeout 120 \ |
| --access-logfile - \ |
| --error-logfile - |
| ``` |
|
|
| ## Docker |
|
|
| ### Build |
|
|
| ```bash |
| # Build l'image |
| docker build -t routeur-ia-api:latest . |
| |
| # Vérifier |
| docker images | grep routeur-ia-api |
| ``` |
|
|
| ### Run |
|
|
| ```bash |
| # Lancer le conteneur |
| docker run -d \ |
| --name routeur-ia-api \ |
| -p 7860:7860 \ |
| --env-file .env \ |
| --restart unless-stopped \ |
| routeur-ia-api:latest |
| |
| # Logs |
| docker logs -f routeur-ia-api |
| |
| # Arrêter |
| docker stop routeur-ia-api |
| |
| # Supprimer |
| docker rm routeur-ia-api |
| ``` |
|
|
| ### Docker Compose |
|
|
| Créer `docker-compose.yml`: |
|
|
| ```yaml |
| version: '3.8' |
| |
| services: |
| api: |
| build: . |
| ports: |
| - "7860:7860" |
| env_file: |
| - .env |
| restart: unless-stopped |
| healthcheck: |
| test: ["CMD", "curl", "-f", "http://localhost:7860/health"] |
| interval: 30s |
| timeout: 10s |
| retries: 3 |
| start_period: 40s |
| deploy: |
| resources: |
| limits: |
| cpus: '2' |
| memory: 2G |
| |
| # Optionnel: Ajouter Redis pour cache |
| # redis: |
| # image: redis:7-alpine |
| # ports: |
| # - "6379:6379" |
| # restart: unless-stopped |
| ``` |
|
|
| Lancement: |
| ```bash |
| docker-compose up -d |
| docker-compose logs -f |
| docker-compose down |
| ``` |
|
|
| ## Cloud Providers |
|
|
| ### Hugging Face Spaces |
|
|
| Le projet est déjà configuré pour Hugging Face Spaces: |
|
|
| 1. Créer un Space sur https://huggingface.co/spaces |
| 2. Choisir "Docker" comme SDK |
| 3. Ajouter les secrets dans les Settings: |
| - `OPENAI_API_KEY` |
| - `MISTRALAI_API_KEY` |
| - `JWT_SECRET_KEY` |
| 4. Push le code |
|
|
| Le `Dockerfile` et `README.md` sont déjà configurés. |
|
|
| ### AWS EC2 |
|
|
| ```bash |
| # Se connecter à l'instance |
| ssh -i key.pem ubuntu@<ip> |
| |
| # Installer Docker |
| curl -fsSL https://get.docker.com -o get-docker.sh |
| sudo sh get-docker.sh |
| |
| # Cloner le projet |
| git clone <repo-url> |
| cd routeur_ia_api |
| |
| # Créer .env avec les clés |
| nano .env |
| |
| # Lancer avec Docker Compose |
| docker-compose up -d |
| |
| # Configurer nginx comme reverse proxy (optionnel) |
| sudo apt install nginx |
| sudo nano /etc/nginx/sites-available/api |
| ``` |
|
|
| Configuration nginx: |
| ```nginx |
| server { |
| listen 80; |
| server_name api.example.com; |
| |
| location / { |
| proxy_pass http://localhost:7860; |
| proxy_http_version 1.1; |
| proxy_set_header Upgrade $http_upgrade; |
| proxy_set_header Connection 'upgrade'; |
| proxy_set_header Host $host; |
| proxy_cache_bypass $http_upgrade; |
| proxy_set_header X-Real-IP $remote_addr; |
| proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; |
| } |
| } |
| ``` |
|
|
| ### Google Cloud Run |
|
|
| ```bash |
| # Build et push vers GCR |
| gcloud builds submit --tag gcr.io/PROJECT_ID/routeur-ia-api |
| |
| # Déployer |
| gcloud run deploy routeur-ia-api \ |
| --image gcr.io/PROJECT_ID/routeur-ia-api \ |
| --platform managed \ |
| --region us-central1 \ |
| --allow-unauthenticated \ |
| --set-env-vars "OPENAI_API_KEY=...,MISTRALAI_API_KEY=...,JWT_SECRET_KEY=..." |
| ``` |
|
|
| ### Azure Container Instances |
|
|
| ```bash |
| # Créer un groupe de ressources |
| az group create --name routeur-ia-rg --location eastus |
| |
| # Créer un registre de conteneurs |
| az acr create --resource-group routeur-ia-rg --name routeuriaacr --sku Basic |
| |
| # Build et push |
| az acr build --registry routeuriaacr --image routeur-ia-api:latest . |
| |
| # Déployer |
| az container create \ |
| --resource-group routeur-ia-rg \ |
| --name routeur-ia-api \ |
| --image routeuriaacr.azurecr.io/routeur-ia-api:latest \ |
| --dns-name-label routeur-ia-api \ |
| --ports 7860 \ |
| --environment-variables \ |
| OPENAI_API_KEY=... \ |
| MISTRALAI_API_KEY=... \ |
| JWT_SECRET_KEY=... |
| ``` |
|
|
| ### Heroku |
|
|
| ```bash |
| # Installer Heroku CLI |
| curl https://cli-assets.heroku.com/install.sh | sh |
| |
| # Login |
| heroku login |
| |
| # Créer app |
| heroku create routeur-ia-api |
| |
| # Ajouter variables d'environnement |
| heroku config:set OPENAI_API_KEY=... |
| heroku config:set MISTRALAI_API_KEY=... |
| heroku config:set JWT_SECRET_KEY=... |
| |
| # Déployer |
| git push heroku main |
| ``` |
|
|
| ## Monitoring |
|
|
| ### LangSmith |
|
|
| Activez dans `.env`: |
| ```env |
| LANGCHAIN_TRACING_V2=true |
| LANGCHAIN_API_KEY=your-key |
| LANGCHAIN_PROJECT=routeur-ia |
| ``` |
|
|
| ### Logs |
|
|
| ```bash |
| # Docker logs |
| docker logs -f routeur-ia-api |
| |
| # Export vers fichier |
| docker logs routeur-ia-api > logs.txt 2>&1 |
| |
| # Avec rotation (production) |
| docker run -d \ |
| --log-driver json-file \ |
| --log-opt max-size=10m \ |
| --log-opt max-file=3 \ |
| routeur-ia-api |
| ``` |
|
|
| ### Prometheus + Grafana (À implémenter) |
|
|
| ```yaml |
| # docker-compose.yml |
| services: |
| prometheus: |
| image: prom/prometheus |
| ports: |
| - "9090:9090" |
| volumes: |
| - ./prometheus.yml:/etc/prometheus/prometheus.yml |
| |
| grafana: |
| image: grafana/grafana |
| ports: |
| - "3000:3000" |
| environment: |
| - GF_SECURITY_ADMIN_PASSWORD=admin |
| ``` |
|
|
| ### Health Checks |
|
|
| ```bash |
| # Vérifier la santé de l'API |
| curl http://localhost:7860/health |
| |
| # Script de monitoring |
| while true; do |
| status=$(curl -s http://localhost:7860/health | jq -r '.status') |
| if [ "$status" != "healthy" ]; then |
| echo "API is down!" |
| # Envoyer alerte |
| fi |
| sleep 60 |
| done |
| ``` |
|
|
| ## Sécurité |
|
|
| ### Checklist Production |
|
|
| - [ ] **HTTPS obligatoire** |
| ```nginx |
| # Redirect HTTP to HTTPS |
| server { |
| listen 80; |
| return 301 https://$host$request_uri; |
| } |
| ``` |
|
|
| - [ ] **Secrets sécurisés** |
| ```bash |
| # Ne jamais commiter .env |
| # Utiliser un gestionnaire de secrets (AWS Secrets Manager, etc.) |
| ``` |
|
|
| - [ ] **CORS restreint** |
| ```python |
| # app.py |
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["https://votresite.com"], # Pas "*" |
| allow_credentials=True, |
| allow_methods=["GET", "POST"], |
| allow_headers=["Authorization", "Content-Type"], |
| ) |
| ``` |
|
|
| - [ ] **Rate limiting** |
| ```python |
| # À implémenter avec slowapi |
| from slowapi import Limiter |
| limiter = Limiter(key_func=get_remote_address) |
| |
| @app.post("/completion") |
| @limiter.limit("10/minute") |
| async def complete(...): |
| ... |
| ``` |
|
|
| - [ ] **JWT robuste** |
| ```bash |
| # Générer avec au moins 32 bytes |
| python -c "import secrets; print(secrets.token_urlsafe(32))" |
| ``` |
|
|
| - [ ] **Validation stricte** |
| - Déjà implémentée avec Pydantic |
| - Taille max fichiers audio: 25 MB |
|
|
| - [ ] **Headers de sécurité** |
| - Déjà implémentés dans `SecurityHeadersMiddleware` |
|
|
| - [ ] **Logs sans données sensibles** |
| ```python |
| # Ne jamais logger les tokens ou clés API |
| logger.info(f"User {user_id} requested completion") # OK |
| logger.info(f"Token: {token}") # JAMAIS! |
| ``` |
|
|
| ### Firewall |
|
|
| ```bash |
| # UFW (Ubuntu) |
| sudo ufw allow 22/tcp # SSH |
| sudo ufw allow 80/tcp # HTTP |
| sudo ufw allow 443/tcp # HTTPS |
| sudo ufw enable |
| |
| # Bloquer accès direct au port 7860 si derrière reverse proxy |
| # Autoriser seulement depuis localhost |
| ``` |
|
|
| ### SSL/TLS |
|
|
| ```bash |
| # Avec Let's Encrypt (gratuit) |
| sudo apt install certbot python3-certbot-nginx |
| sudo certbot --nginx -d api.example.com |
| |
| # Renouvellement automatique |
| sudo certbot renew --dry-run |
| ``` |
|
|
| ## Performance |
|
|
| ### Optimisations |
|
|
| 1. **Workers multiples** |
| ```bash |
| uvicorn app:app --workers 4 |
| ``` |
|
|
| 2. **Connection pooling** |
| - À implémenter pour base de données future |
|
|
| 3. **Cache Redis** |
| ```python |
| # À implémenter |
| @cache.cached(timeout=300) |
| async def list_models(): |
| ... |
| ``` |
|
|
| 4. **Compression** |
| ```python |
| from fastapi.middleware.gzip import GZipMiddleware |
| app.add_middleware(GZipMiddleware, minimum_size=1000) |
| ``` |
|
|
| 5. **CDN pour assets** |
| - Si vous servez du contenu statique |
|
|
| ## Backup |
|
|
| ### Base de données (future) |
|
|
| ```bash |
| # Backup automatique quotidien |
| 0 2 * * * /usr/bin/docker exec postgres pg_dump -U user db > /backups/db_$(date +\%Y\%m\%d).sql |
| ``` |
|
|
| ### Configuration |
|
|
| ```bash |
| # Backup .env et configuration |
| tar -czf backup_$(date +%Y%m%d).tar.gz .env config/ |
| ``` |
|
|
| ## Troubleshooting |
|
|
| ### L'API ne démarre pas |
|
|
| ```bash |
| # Vérifier les logs |
| docker logs routeur-ia-api |
| |
| # Vérifier les variables d'environnement |
| docker exec routeur-ia-api env | grep API_KEY |
| |
| # Vérifier le port |
| netstat -tlnp | grep 7860 |
| ``` |
|
|
| ### Erreurs de connexion |
|
|
| ```bash |
| # Tester depuis le conteneur |
| docker exec routeur-ia-api curl http://localhost:7860/health |
| |
| # Tester le réseau |
| docker network inspect bridge |
| ``` |
|
|
| ### Performance lente |
|
|
| ```bash |
| # Vérifier les ressources |
| docker stats routeur-ia-api |
| |
| # Augmenter les workers |
| # Ajouter cache Redis |
| # Optimiser les requêtes |
| ``` |
|
|
| ### Erreurs JWT |
|
|
| ```bash |
| # Vérifier JWT_SECRET_KEY dans .env |
| # Régénérer les tokens |
| # Vérifier l'expiration (JWT_EXPIRATION_MINUTES) |
| ``` |
|
|
| ## Rollback |
|
|
| ```bash |
| # Docker |
| docker tag routeur-ia-api:latest routeur-ia-api:backup |
| docker pull routeur-ia-api:previous |
| docker stop routeur-ia-api |
| docker run ... routeur-ia-api:previous |
| |
| # Git |
| git revert HEAD |
| git push |
| ``` |
|
|
| ## Checklist de Déploiement |
|
|
| - [ ] Variables d'environnement configurées |
| - [ ] JWT_SECRET_KEY généré sécurisement |
| - [ ] CORS configuré pour production |
| - [ ] HTTPS activé |
| - [ ] Logs configurés |
| - [ ] Monitoring en place |
| - [ ] Health checks fonctionnels |
| - [ ] Backup automatique configuré |
| - [ ] Firewall configuré |
| - [ ] Documentation à jour |
| - [ ] Tests effectués en staging |
| - [ ] Plan de rollback prêt |
|
|
| --- |
|
|
| **Important**: Toujours tester en environnement de staging avant production! |
|
|
|
|