# Guide de déploiement — Imago sur serveur Docker > Cible : serveur Docker distant (VM Proxmox, VPS, ou bare metal) > Prérequis : Docker 24+, Docker Compose v2, accès SSH --- ## Étape 1 — Préparer le registry d'images Choisir UNE des options : ### Option A : Gitea Container Registry (recommandé si Gitea dispo) ```bash # Builder et tagger l'image cd C:\dev\git\python\imago docker build -t gitea.dracodev.net/projets/imago-backend:latest . docker build -t gitea.dracodev.net/projets/imago-admin:latest ./imago-admin # Se connecter au registry Gitea docker login gitea.dracodev.net -u bruno # Pusher docker push gitea.dracodev.net/projets/imago-backend:latest docker push gitea.dracodev.net/projets/imago-admin:latest ``` ### Option B : Docker Hub ```bash docker build -t tonuser/imago-backend:latest . docker build -t tonuser/imago-admin:latest ./imago-admin docker push tonuser/imago-backend:latest docker push tonuser/imago-admin:latest ``` ### Option C : Registry local sur le serveur ```bash # Sur le serveur cible docker run -d -p 5000:5000 --name registry registry:2 # En local, builder et pusher docker build -t localhost:5000/imago-backend:latest . docker push localhost:5000/imago-backend:latest ``` --- ## Étape 2 — Préparer les secrets de production ```bash # Générer des secrets forts (à faire UNE SEULE fois) openssl rand -hex 32 # SECRET_KEY openssl rand -hex 32 # ADMIN_API_KEY → note-la, c'est ta clé d'accès admin openssl rand -hex 32 # JWT_SECRET_KEY openssl rand -hex 32 # SIGNED_URL_SECRET openssl rand -hex 16 # S3_SECRET_KEY openssl rand -hex 16 # MINIO_ROOT_PASSWORD openssl rand -hex 16 # POSTGRES_PASSWORD ``` Créer le fichier `.env.production` : ```bash # ── Application ── APP_NAME=Imago APP_VERSION=2.0.0 DEBUG=false SECRET_KEY= # ── Base de données ── DATABASE_URL=postgresql+asyncpg://imago:@db:5432/imago # ── Stockage S3/MinIO ── STORAGE_BACKEND=s3 S3_BUCKET=imago S3_ENDPOINT_URL=http://minio:9000 S3_ACCESS_KEY=minioadmin S3_SECRET_KEY= S3_REGION=us-east-1 SIGNED_URL_SECRET= # ── Redis ── REDIS_URL=redis://redis:***@ADMIN_API_KEY= JWT_SECRET_KEY= JWT_ALGORITHM=HS256 # ── AI ── AI_ENABLED=true AI_PROVIDER=openrouter OPENROUTER_API_KEY= OPENROUTER_MODEL=qwen/qwen2.5-vl-72b-instruct AI_TAGS_MIN=5 AI_TAGS_MAX=10 AI_DESCRIPTION_LANGUAGE=francais AI_REQUEST_TIMEOUT=60 AI_MAX_RETRIES=2 # ── OCR ── OCR_ENABLED=true OCR_LANGUAGES=fra+eng # ── CORS ── CORS_ORIGINS=["https://admin.ton-domaine.com"] # ── Pipeline ── PIPELINE_TIMEOUT=300 PIPELINE_MAX_RETRIES=3 # ── Rate Limiting (Redis persistence) ── RATE_LIMIT_STORAGE_URL=redis://redis:6379/1 ``` --- ## Étape 3 — Préparer le docker-compose.production.yml ```yaml services: traefik: image: traefik:v3.0 command: - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=bruno.charest@gmail.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - traefik_certs:/letsencrypt restart: unless-stopped backend: image: gitea.dracodev.net/projets/imago-backend:latest env_file: .env.production labels: - "traefik.enable=true" - "traefik.http.routers.imago-api.rule=Host(`api.ton-domaine.com`)" - "traefik.http.routers.imago-api.entrypoints=websecure" - "traefik.http.routers.imago-api.tls.certresolver=letsencrypt" depends_on: db: condition: service_healthy redis: condition: service_healthy restart: unless-stopped deploy: resources: limits: memory: 1G cpus: '2' worker: image: gitea.dracodev.net/projets/imago-backend:latest command: python worker.py env_file: .env.production depends_on: db: condition: service_healthy redis: condition: service_healthy restart: unless-stopped deploy: resources: limits: memory: 512M cpus: '1' admin: image: nginx:alpine ports: - "127.0.0.1:3000:80" volumes: - ./admin-dist:/usr/share/nginx/html:ro labels: - "traefik.enable=true" - "traefik.http.routers.imago-admin.rule=Host(`admin.ton-domaine.com`)" - "traefik.http.routers.imago-admin.entrypoints=websecure" - "traefik.http.routers.imago-admin.tls.certresolver=letsencrypt" restart: unless-stopped db: image: postgres:16-alpine env_file: .env.production environment: POSTGRES_USER: imago POSTGRES_DB: imago volumes: - pgdata:/var/lib/postgresql/data - ./backups:/backups healthcheck: test: ["CMD-SHELL", "pg_isready -U imago -d imago"] interval: 5s timeout: 5s retries: 5 restart: unless-stopped deploy: resources: limits: memory: 512M redis: image: redis:7-alpine command: redis-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru volumes: - redisdata:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 3 restart: unless-stopped deploy: resources: limits: memory: 256M minio: image: minio/minio command: server /data --console-address ":9001" env_file: .env.production volumes: - miniodata:/data restart: unless-stopped deploy: resources: limits: memory: 512M volumes: pgdata: redisdata: miniodata: traefik_certs: ``` --- ## Étape 4 — Déployer sur le serveur ```bash # 1. Se connecter au serveur ssh ton-serveur # 2. Créer le répertoire de l'application mkdir -p /opt/imago && cd /opt/imago # 3. Copier les fichiers de configuration # (depuis ton poste local) scp docker-compose.production.yml ton-serveur:/opt/imago/ scp .env.production ton-serveur:/opt/imago/ # 4. S'assurer que les volumes de backup existent mkdir -p backups # 5. Démarrer la stack docker compose -f docker-compose.production.yml up -d # 6. Vérifier les logs docker compose -f docker-compose.production.yml logs -f backend # 7. Vérifier la santé curl https://api.ton-domaine.com/health ``` --- ## Étape 5 — Backup automatique (cron) Ajouter au crontab du serveur : ```cron # Backup PostgreSQL — tous les jours à 2h 0 2 * * * docker exec imago-db-1 pg_dump -U imago imago > /opt/imago/backups/imago_$(date +\%Y\%m\%d).sql # Nettoyer les backups de plus de 30 jours 0 3 * * * find /opt/imago/backups -name "*.sql" -mtime +30 -delete ``` --- ## Étape 6 — Vérifications post-déploiement - [ ] `https://api.ton-domaine.com/health` → `{"status":"healthy"}` - [ ] `https://api.ton-domaine.com/health/detailed` → tous les checks OK - [ ] `https://admin.ton-domaine.com` → page de login accessible - [ ] Connexion admin avec `ADMIN_API_KEY` - [ ] Upload d'une image test → pipeline OK - [ ] WebSocket `/ws/pipeline/{id}` → événements reçus - [ ] Métriques Prometheus `/metrics` → données présentes --- ## Résumé des commandes rapides ```bash # Builder les images (local) docker build -t gitea.dracodev.net/projets/imago-backend:latest . docker login gitea.dracodev.net docker push gitea.dracodev.net/projets/imago-backend:latest # Déployer (serveur) ssh serveur "cd /opt/imago && docker compose pull && docker compose up -d" # Vérifier curl https://api.ton-domaine.com/health ```