Update deploy doc to use docker-registry.dev.home:5000 + production compose
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
# ═══════════════════════════════════════════════════════════════
|
||||||
|
# Imago — Docker Compose Production
|
||||||
|
# ═══════════════════════════════════════════════════════════════
|
||||||
|
# Utilise l'image depuis le registry local (pas de build).
|
||||||
|
# Déploiement : copier ce fichier + .env.production sur le serveur.
|
||||||
|
#
|
||||||
|
# Usage :
|
||||||
|
# docker compose -f docker-compose.production.yml up -d
|
||||||
|
# docker compose -f docker-compose.production.yml pull # mise à jour
|
||||||
|
# ═══════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
|
services:
|
||||||
|
# ── API Backend ────────────────────────────────────────────
|
||||||
|
backend:
|
||||||
|
image: docker-registry.dev.home:5000/imago-backend:latest
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
env_file: .env.production
|
||||||
|
volumes:
|
||||||
|
- uploads:/app/data/uploads
|
||||||
|
- thumbnails:/app/data/thumbnails
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ── Worker ARQ (pipeline AI) ───────────────────────────────
|
||||||
|
worker:
|
||||||
|
image: docker-registry.dev.home:5000/imago-backend:latest
|
||||||
|
command: python worker.py
|
||||||
|
env_file: .env.production
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ── PostgreSQL ─────────────────────────────────────────────
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: imago
|
||||||
|
POSTGRES_DB: imago
|
||||||
|
env_file: .env.production
|
||||||
|
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
|
||||||
|
|
||||||
|
# ── Redis ──────────────────────────────────────────────────
|
||||||
|
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
|
||||||
|
|
||||||
|
# ── MinIO (stockage S3) ────────────────────────────────────
|
||||||
|
minio:
|
||||||
|
image: minio/minio
|
||||||
|
command: server /data --console-address ":9001"
|
||||||
|
env_file: .env.production
|
||||||
|
environment:
|
||||||
|
MINIO_ROOT_USER: minioadmin
|
||||||
|
volumes:
|
||||||
|
- miniodata:/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
||||||
|
redisdata:
|
||||||
|
miniodata:
|
||||||
|
uploads:
|
||||||
|
thumbnails:
|
||||||
+38
-224
@@ -1,46 +1,28 @@
|
|||||||
# Guide de déploiement — Imago sur serveur Docker
|
# Guide de déploiement — Imago sur serveur Docker
|
||||||
|
|
||||||
> Cible : serveur Docker distant (VM Proxmox, VPS, ou bare metal)
|
> Cible : serveur Docker du lab (dev.lab.home / Proxmox)
|
||||||
|
> Registry : `docker-registry.dev.home:5000`
|
||||||
> Prérequis : Docker 24+, Docker Compose v2, accès SSH
|
> Prérequis : Docker 24+, Docker Compose v2, accès SSH
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Étape 1 — Préparer le registry d'images
|
## Étape 1 — Builder et pousser l'image vers le registry
|
||||||
|
|
||||||
Choisir UNE des options :
|
Depuis le poste de développement (Windows + WSL Debian) :
|
||||||
|
|
||||||
### Option A : Gitea Container Registry (recommandé si Gitea dispo)
|
```powershell
|
||||||
```bash
|
cd C:\dev\git\python\imago\docker
|
||||||
# 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
|
# Builder l'image
|
||||||
docker login gitea.dracodev.net -u bruno
|
.\build-img.ps1
|
||||||
|
|
||||||
# Pusher
|
# Pousser vers le registry (version semver auto-incrémentée)
|
||||||
docker push gitea.dracodev.net/projets/imago-backend:latest
|
.\deploy-img.ps1
|
||||||
docker push gitea.dracodev.net/projets/imago-admin:latest
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option B : Docker Hub
|
L'image est disponible à :
|
||||||
```bash
|
- `docker-registry.dev.home:5000/imago-backend:latest`
|
||||||
docker build -t tonuser/imago-backend:latest .
|
- `docker-registry.dev.home:5000/imago-backend:2.0.0`
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -49,15 +31,15 @@ docker push localhost:5000/imago-backend:latest
|
|||||||
```bash
|
```bash
|
||||||
# Générer des secrets forts (à faire UNE SEULE fois)
|
# Générer des secrets forts (à faire UNE SEULE fois)
|
||||||
openssl rand -hex 32 # SECRET_KEY
|
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 # ADMIN_API_KEY → note-la, c'est ta clé admin
|
||||||
openssl rand -hex 32 # JWT_SECRET_KEY
|
openssl rand -hex 32 # JWT_SECRET_KEY
|
||||||
openssl rand -hex 32 # SIGNED_URL_SECRET
|
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 # MINIO_ROOT_PASSWORD
|
||||||
openssl rand -hex 16 # POSTGRES_PASSWORD
|
openssl rand -hex 16 # POSTGRES_PASSWORD
|
||||||
```
|
```
|
||||||
|
|
||||||
Créer le fichier `.env.production` :
|
Créer `.env.production` (remplacer les `<...>`) :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ── Application ──
|
# ── Application ──
|
||||||
APP_NAME=Imago
|
APP_NAME=Imago
|
||||||
@@ -68,7 +50,7 @@ SECRET_KEY=<valeur générée>
|
|||||||
# ── Base de données ──
|
# ── Base de données ──
|
||||||
DATABASE_URL=postgresql+asyncpg://imago:<POSTGRES_PASSWORD>@db:5432/imago
|
DATABASE_URL=postgresql+asyncpg://imago:<POSTGRES_PASSWORD>@db:5432/imago
|
||||||
|
|
||||||
# ── Stockage S3/MinIO ──
|
# ── Stockage MinIO ──
|
||||||
STORAGE_BACKEND=s3
|
STORAGE_BACKEND=s3
|
||||||
S3_BUCKET=imago
|
S3_BUCKET=imago
|
||||||
S3_ENDPOINT_URL=http://minio:9000
|
S3_ENDPOINT_URL=http://minio:9000
|
||||||
@@ -85,7 +67,7 @@ JWT_ALGORITHM=HS256
|
|||||||
# ── AI ──
|
# ── AI ──
|
||||||
AI_ENABLED=true
|
AI_ENABLED=true
|
||||||
AI_PROVIDER=openrouter
|
AI_PROVIDER=openrouter
|
||||||
OPENROUTER_API_KEY=<ta clé OpenRouter>
|
OPENROUTER_API_KEY=<clé OpenRouter>
|
||||||
OPENROUTER_MODEL=qwen/qwen2.5-vl-72b-instruct
|
OPENROUTER_MODEL=qwen/qwen2.5-vl-72b-instruct
|
||||||
AI_TAGS_MIN=5
|
AI_TAGS_MIN=5
|
||||||
AI_TAGS_MAX=10
|
AI_TAGS_MAX=10
|
||||||
@@ -98,179 +80,14 @@ OCR_ENABLED=true
|
|||||||
OCR_LANGUAGES=fra+eng
|
OCR_LANGUAGES=fra+eng
|
||||||
|
|
||||||
# ── CORS ──
|
# ── CORS ──
|
||||||
CORS_ORIGINS=["https://admin.ton-domaine.com"]
|
CORS_ORIGINS=["http://localhost:3000", "http://localhost:8000"]
|
||||||
|
|
||||||
# ── Pipeline ──
|
# ── Pipeline ──
|
||||||
PIPELINE_TIMEOUT=300
|
PIPELINE_TIMEOUT=300
|
||||||
PIPELINE_MAX_RETRIES=3
|
PIPELINE_MAX_RETRIES=3
|
||||||
|
|
||||||
# ── Rate Limiting (Redis persistence) ──
|
# ── Rate Limiting (Redis persistence) ──
|
||||||
RATE_LIMIT_STORAGE_URL=redis://redis:6379/1
|
RATE_LIMIT_STORAGE_URL=redis://redis:***@#!/bin/bash
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## É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
|
# 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
|
0 2 * * * docker exec imago-db-1 pg_dump -U imago imago > /opt/imago/backups/imago_$(date +\%Y\%m\%d).sql
|
||||||
|
|
||||||
@@ -280,29 +97,26 @@ Ajouter au crontab du serveur :
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Étape 6 — Vérifications post-déploiement
|
## Étape 5 — 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
|
```bash
|
||||||
# Builder les images (local)
|
# Vérifier que tous les conteneurs tournent
|
||||||
docker build -t gitea.dracodev.net/projets/imago-backend:latest .
|
docker compose -f /opt/imago/docker-compose.production.yml ps
|
||||||
docker login gitea.dracodev.net
|
|
||||||
docker push gitea.dracodev.net/projets/imago-backend:latest
|
|
||||||
|
|
||||||
# Déployer (serveur)
|
# Santé de l'API
|
||||||
ssh serveur "cd /opt/imago && docker compose pull && docker compose up -d"
|
curl http://localhost:8000/health
|
||||||
|
|
||||||
# Vérifier
|
# Santé détaillée (tous les services)
|
||||||
curl https://api.ton-domaine.com/health
|
curl http://localhost:8000/health/detailed
|
||||||
|
|
||||||
|
# Accéder au panneau admin
|
||||||
|
curl http://localhost:3000
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Checklist :
|
||||||
|
- [ ] `http://localhost:8000/health` → `{"status":"healthy"}`
|
||||||
|
- [ ] `http://localhost:8000/health/detailed` → tous les checks OK
|
||||||
|
- [ ] `http://localhost:3000` → page de login accessible
|
||||||
|
- [ ] Connexion admin avec `ADMIN_API_KEY`
|
||||||
|
- [ ] Upload d'une image test → pipeline OK
|
||||||
|
- [ ] Métriques Prometheus `/metrics` → données présentes
|
||||||
|
|||||||
Reference in New Issue
Block a user