Files
Imago/docs/DEPLOYMENT.md
T
bruno 314df55221
CI / Lint & Format (push) Failing after 10s
CI / Tests (push) Has been skipped
CI / Security Scan (push) Failing after 8s
CI / Docker Build (push) Has been skipped
Add production deployment guide and checklist
2026-06-22 19:34:03 -04:00

7.7 KiB

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)

# 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

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

# 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

# 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 :

# ── Application ──
APP_NAME=Imago
APP_VERSION=2.0.0
DEBUG=false
SECRET_KEY=<valeur générée>

# ── Base de données ──
DATABASE_URL=postgresql+asyncpg://imago:<POSTGRES_PASSWORD>@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_SECRET_KEY généré>
S3_REGION=us-east-1
SIGNED_URL_SECRET=<valeur générée>

# ── Redis ──
REDIS_URL=redis://redis:***@ADMIN_API_KEY=<valeur générée>
JWT_SECRET_KEY=<valeur générée>
JWT_ALGORITHM=HS256

# ── AI ──
AI_ENABLED=true
AI_PROVIDER=openrouter
OPENROUTER_API_KEY=<ta clé OpenRouter>
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

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

# 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 :

# 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

# 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