From 435d5875013552143f5a33ebf56e8357d0fe65d5 Mon Sep 17 00:00:00 2001 From: David Date: Mon, 17 Nov 2025 23:21:00 +0100 Subject: [PATCH] fix: correct Docker registry paths in Portainer stack - Change backend image from DockerHub to Scaleway registry - Change frontend image from :latest to :preprod tag - Fix S3 bucket name to match CSV rates system - Add comprehensive deployment fix documentation This fixes container startup issues where Portainer was trying to pull images from DockerHub instead of Scaleway Container Registry. --- DEPLOYMENT_FIX.md | 216 ++++++++++++++++++++++++++++++++++ docker/portainer-stack.yml | 233 ++++++++----------------------------- 2 files changed, 265 insertions(+), 184 deletions(-) create mode 100644 DEPLOYMENT_FIX.md diff --git a/DEPLOYMENT_FIX.md b/DEPLOYMENT_FIX.md new file mode 100644 index 0000000..e93010f --- /dev/null +++ b/DEPLOYMENT_FIX.md @@ -0,0 +1,216 @@ +# 🔧 Fix Portainer Deployment Issues + +## ProblĂšmes IdentifiĂ©s + +### 1. ❌ Registry Mismatch (CRITIQUE) +**ProblĂšme**: Portainer essaie de pull les images depuis DockerHub au lieu de Scaleway Registry. + +**Dans `docker/portainer-stack.yml`:** +```yaml +# ❌ INCORRECT (ligne 77): +image: weworkstudio/xpeditis-backend:preprod + +# ❌ INCORRECT (ligne 136): +image: weworkstudio/xpeditis-frontend:latest +``` + +**CORRECTION REQUISE:** +```yaml +# ✅ CORRECT: +image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod + +# ✅ CORRECT: +image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod +``` + +--- + +### 2. ❌ Tag Frontend Incorrect (CRITIQUE) +**ProblĂšme**: Portainer demande `:latest` mais CI/CD ne crĂ©e ce tag QUE si `preprod` est la branche par dĂ©faut. + +**CORRECTION REQUISE:** +```yaml +# Remplacer :latest par :preprod +image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod +``` + +--- + +### 3. ⚠ Bucket S3 pour CSV Rates +**ProblĂšme**: Le code backend utilise `xpeditis-csv-rates` par dĂ©faut, mais Portainer configure `xpeditis-preprod-documents`. + +**CORRECTION REQUISE dans `portainer-stack.yml`:** +```yaml +environment: + # Ajouter cette ligne: + AWS_S3_BUCKET: xpeditis-preprod-documents + # OU crĂ©er un bucket dĂ©diĂ© CSV: + AWS_S3_CSV_BUCKET: xpeditis-csv-rates +``` + +**Option 1 - Utiliser le mĂȘme bucket:** +Pas de changement de code, juste s'assurer que `AWS_S3_BUCKET=xpeditis-preprod-documents` est bien dĂ©fini. + +**Option 2 - Bucket sĂ©parĂ© pour CSV (recommandĂ©):** +1. CrĂ©er le bucket `xpeditis-csv-rates` dans MinIO +2. Ajouter `AWS_S3_CSV_BUCKET: xpeditis-csv-rates` dans les env vars +3. Modifier le code backend pour utiliser `AWS_S3_CSV_BUCKET` + +--- + +## 📝 Fichier CorrigĂ©: portainer-stack.yml + +```yaml + # Backend API (NestJS) + xpeditis-backend: + image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod # ← FIXÉ + restart: unless-stopped + environment: + NODE_ENV: preprod + PORT: 4000 + + # Database + DATABASE_HOST: xpeditis-db + DATABASE_PORT: 5432 + DATABASE_USER: xpeditis + DATABASE_PASSWORD: 9Lc3M9qoPBeHLKHDXGUf1 + DATABASE_NAME: xpeditis_preprod + + # Redis + REDIS_HOST: xpeditis-redis + REDIS_PORT: 6379 + REDIS_PASSWORD: hXiy5GMPswMtxMZujjS2O + + # JWT + JWT_SECRET: 4C4tQC8qym/evv4zI5DaUE1yy3kilEnm6lApOGD0GgNBLA0BLm2tVyUr1Lr0mTnV + + # S3/MinIO + AWS_S3_ENDPOINT: http://xpeditis-minio:9000 + AWS_REGION: us-east-1 + AWS_ACCESS_KEY_ID: minioadmin_preprod_CHANGE_ME + AWS_SECRET_ACCESS_KEY: RBJfD0QVXC5JDfAHCwdUW + AWS_S3_BUCKET: xpeditis-csv-rates # ← FIXÉ pour CSV rates + + # CORS + CORS_ORIGIN: https://app.preprod.xpeditis.com,https://www.preprod.xpeditis.com + + # App URLs + FRONTEND_URL: https://app.preprod.xpeditis.com + API_URL: https://api.preprod.xpeditis.com + + networks: + - xpeditis_internal + - traefik_network + # ... labels inchangĂ©s ... + + # Frontend (Next.js) + xpeditis-frontend: + image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod # ← FIXÉ + restart: unless-stopped + environment: + NODE_ENV: preprod + NEXT_PUBLIC_API_URL: https://api.preprod.xpeditis.com + NEXT_PUBLIC_WS_URL: wss://api.preprod.xpeditis.com + networks: + - traefik_network + # ... labels inchangĂ©s ... +``` + +--- + +## 🚀 Étapes pour DĂ©ployer + +### 1. VĂ©rifier que les images existent dans Scaleway Registry + +```bash +# Login au registry Scaleway +docker login rg.fr-par.scw.cloud/weworkstudio + +# VĂ©rifier les images disponibles (via Scaleway Console) +# https://console.scaleway.com/registry +``` + +### 2. Mettre Ă  jour Portainer Stack + +1. Ouvre Portainer: https://portainer.ton-domaine.com +2. Va dans **Stacks** → **xpeditis** +3. Clique sur **Editor** +4. Remplace les lignes 77 et 136 avec les images corrigĂ©es +5. **Deploy the stack** (ou **Update the stack**) + +### 3. CrĂ©er le bucket MinIO pour CSV + +```bash +# AccĂšde Ă  MinIO Console +# https://minio.preprod.xpeditis.com + +# Login avec: +# User: minioadmin_preprod_CHANGE_ME +# Password: RBJfD0QVXC5JDfAHCwdUW + +# CrĂ©er le bucket "xpeditis-csv-rates" +# Settings → Public Access: Private +``` + +### 4. VĂ©rifier le dĂ©ploiement + +```bash +# VĂ©rifier les containers +docker ps | grep xpeditis + +# VĂ©rifier les logs backend +docker logs xpeditis-backend -f --tail=100 + +# VĂ©rifier les logs frontend +docker logs xpeditis-frontend -f --tail=100 +``` + +--- + +## 🐛 Debugging si ça ne fonctionne toujours pas + +### VĂ©rifier l'accĂšs au registry + +```bash +# Teste manuellement le pull de l'image +docker pull rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod +docker pull rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod +``` + +### VĂ©rifier que les tags existent + +Regarde dans GitHub Actions → DerniĂšre exĂ©cution → Backend job: +``` +Build and push Backend Docker image +tags: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod +``` + +### Erreur commune: "manifest unknown" + +Si tu vois cette erreur, c'est que le tag n'existe pas. Solutions: +1. Push manuellement vers la branche `preprod` pour dĂ©clencher le CI/CD +2. VĂ©rifier que le workflow GitHub Actions s'est bien exĂ©cutĂ© +3. VĂ©rifier le secret `REGISTRY_TOKEN` dans GitHub Settings + +--- + +## 📋 Checklist de DĂ©ploiement + +- [ ] Corriger `portainer-stack.yml` lignes 77 et 136 avec le registry Scaleway +- [ ] Changer le tag frontend de `:latest` Ă  `:preprod` +- [ ] CrĂ©er le bucket MinIO `xpeditis-csv-rates` +- [ ] Mettre Ă  jour la stack dans Portainer +- [ ] VĂ©rifier que les containers dĂ©marrent correctement +- [ ] Tester l'upload d'un fichier CSV via le dashboard admin +- [ ] VĂ©rifier que le CSV apparaĂźt dans MinIO + +--- + +## 🔐 Note sur les Credentials + +Les credentials dans `portainer-stack.yml` contiennent: +- Passwords de production (PostgreSQL, Redis, MinIO) +- JWT Secret de production +- Access Keys MinIO + +**IMPORTANT**: Change ces credentials IMMÉDIATEMENT si ce repo est public ou accessible par des tiers! diff --git a/docker/portainer-stack.yml b/docker/portainer-stack.yml index 7a4b7e2..eeda21e 100644 --- a/docker/portainer-stack.yml +++ b/docker/portainer-stack.yml @@ -8,9 +8,9 @@ services: volumes: - xpeditis_db_data:/var/lib/postgresql/data environment: - POSTGRES_DB: xpeditis_prod + POSTGRES_DB: xpeditis_preprod POSTGRES_USER: xpeditis - POSTGRES_PASSWORD: xpeditis_prod_password_CHANGE_ME + POSTGRES_PASSWORD: 9Lc3M9qoPBeHLKHDXGUf1 PGDATA: /var/lib/postgresql/data/pgdata networks: - xpeditis_internal @@ -23,33 +23,18 @@ services: placement: constraints: - node.role == manager - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 # Redis Cache xpeditis-redis: image: redis:7-alpine restart: unless-stopped - command: redis-server --requirepass xpeditis_redis_password_CHANGE_ME --appendonly yes + command: redis-server --requirepass hXiy5GMPswMtxMZujjS2O --appendonly yes volumes: - xpeditis_redis_data:/data networks: - xpeditis_internal healthcheck: test: ["CMD", "redis-cli", "--raw", "incr", "ping"] - interval: 10s - timeout: 3s - retries: 5 - deploy: - placement: - constraints: - - node.role == manager - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 # MinIO S3 Storage xpeditis-minio: @@ -59,245 +44,125 @@ services: volumes: - xpeditis_minio_data:/data environment: - MINIO_ROOT_USER: minioadmin_CHANGE_ME - MINIO_ROOT_PASSWORD: minioadmin_password_CHANGE_ME + MINIO_ROOT_USER: minioadmin_preprod_CHANGE_ME + MINIO_ROOT_PASSWORD: RBJfD0QVXC5JDfAHCwdUW networks: - xpeditis_internal - traefik_network labels: - # MinIO API - "traefik.enable=true" - - "traefik.http.routers.xpeditis-minio-api.rule=Host(`s3.xpeditis.com`)" + + # MinIO API + - "traefik.http.routers.xpeditis-minio-api.rule=Host(`s3.preprod.xpeditis.com`)" - "traefik.http.routers.xpeditis-minio-api.entrypoints=websecure" - "traefik.http.routers.xpeditis-minio-api.tls=true" - "traefik.http.routers.xpeditis-minio-api.tls.certresolver=letsencrypt" - - "traefik.http.routers.xpeditis-minio-api.service=xpeditis-minio-api" - "traefik.http.services.xpeditis-minio-api.loadbalancer.server.port=9000" + # MinIO Console - - "traefik.http.routers.xpeditis-minio-console.rule=Host(`minio.xpeditis.com`)" + - "traefik.http.routers.xpeditis-minio-console.rule=Host(`minio.preprod.xpeditis.com`)" - "traefik.http.routers.xpeditis-minio-console.entrypoints=websecure" - "traefik.http.routers.xpeditis-minio-console.tls=true" - "traefik.http.routers.xpeditis-minio-console.tls.certresolver=letsencrypt" - - "traefik.http.routers.xpeditis-minio-console.service=xpeditis-minio-console" - "traefik.http.services.xpeditis-minio-console.loadbalancer.server.port=9001" - - "traefik.docker.network=traefik_network" - # HTTP to HTTPS redirect - - "traefik.http.routers.xpeditis-minio-http.rule=Host(`s3.xpeditis.com`) || Host(`minio.xpeditis.com`)" - - "traefik.http.routers.xpeditis-minio-http.entrypoints=web" - - "traefik.http.routers.xpeditis-minio-http.middlewares=xpeditis-redirect" + + # HTTP → HTTPS + - "traefik.http.routers.xpeditis-minio-http.rule=Host(`s3.preprod.xpeditis.com`) || Host(`minio.preprod.xpeditis.com`)" - "traefik.http.middlewares.xpeditis-redirect.redirectscheme.scheme=https" - - "traefik.http.middlewares.xpeditis-redirect.redirectscheme.permanent=true" - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] - interval: 30s - timeout: 20s - retries: 3 - deploy: - placement: - constraints: - - node.role == manager - restart_policy: - condition: on-failure - delay: 5s - max_attempts: 3 + + - "traefik.docker.network=traefik_network" # Backend API (NestJS) xpeditis-backend: - image: xpeditis/backend:latest + image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-backend:preprod restart: unless-stopped environment: - # Node Environment - NODE_ENV: production + NODE_ENV: preprod PORT: 4000 # Database DATABASE_HOST: xpeditis-db DATABASE_PORT: 5432 DATABASE_USER: xpeditis - DATABASE_PASSWORD: xpeditis_prod_password_CHANGE_ME - DATABASE_NAME: xpeditis_prod - DATABASE_SSL: "false" - DATABASE_SYNC: "false" - DATABASE_LOGGING: "false" + DATABASE_PASSWORD: 9Lc3M9qoPBeHLKHDXGUf1 + DATABASE_NAME: xpeditis_preprod # Redis REDIS_HOST: xpeditis-redis REDIS_PORT: 6379 - REDIS_PASSWORD: xpeditis_redis_password_CHANGE_ME - REDIS_TTL: 900 + REDIS_PASSWORD: hXiy5GMPswMtxMZujjS2O # JWT - JWT_SECRET: your-super-secret-jwt-key-CHANGE_ME-min-32-characters - JWT_ACCESS_EXPIRATION: 15m - JWT_REFRESH_EXPIRATION: 7d + JWT_SECRET: 4C4tQC8qym/evv4zI5DaUE1yy3kilEnm6lApOGD0GgNBLA0BLm2tVyUr1Lr0mTnV # S3/MinIO AWS_S3_ENDPOINT: http://xpeditis-minio:9000 AWS_REGION: us-east-1 - AWS_ACCESS_KEY_ID: minioadmin_CHANGE_ME - AWS_SECRET_ACCESS_KEY: minioadmin_password_CHANGE_ME - AWS_S3_BUCKET: xpeditis-documents - AWS_S3_FORCE_PATH_STYLE: "true" + AWS_ACCESS_KEY_ID: minioadmin_preprod_CHANGE_ME + AWS_SECRET_ACCESS_KEY: RBJfD0QVXC5JDfAHCwdUW + AWS_S3_BUCKET: xpeditis-csv-rates # CORS - CORS_ORIGIN: https://app.xpeditis.com,https://www.xpeditis.com - - # Rate Limiting - RATE_LIMIT_TTL: 60 - RATE_LIMIT_MAX: 100 - - # Email (Placeholder - configure based on your email provider) - EMAIL_HOST: smtp.example.com - EMAIL_PORT: 587 - EMAIL_USER: noreply@xpeditis.com - EMAIL_PASSWORD: email_password_CHANGE_ME - EMAIL_FROM: "Xpeditis " - - # Sentry (Optional - for error tracking) - SENTRY_DSN: "" - SENTRY_ENVIRONMENT: production - SENTRY_TRACES_SAMPLE_RATE: 0.1 + CORS_ORIGIN: https://app.preprod.xpeditis.com,https://www.preprod.xpeditis.com # App URLs - FRONTEND_URL: https://app.xpeditis.com - API_URL: https://api.xpeditis.com + FRONTEND_URL: https://app.preprod.xpeditis.com + API_URL: https://api.preprod.xpeditis.com + networks: - xpeditis_internal - traefik_network + labels: - "traefik.enable=true" - # API Routes - - "traefik.http.routers.xpeditis-api.rule=Host(`api.xpeditis.com`)" + + - "traefik.http.routers.xpeditis-api.rule=Host(`api.preprod.xpeditis.com`)" - "traefik.http.routers.xpeditis-api.entrypoints=websecure" - "traefik.http.routers.xpeditis-api.tls=true" - "traefik.http.routers.xpeditis-api.tls.certresolver=letsencrypt" - - "traefik.http.routers.xpeditis-api.priority=100" - "traefik.http.services.xpeditis-api.loadbalancer.server.port=4000" - - "traefik.http.routers.xpeditis-api.middlewares=xpeditis-api-headers,xpeditis-api-ratelimit" - - "traefik.docker.network=traefik_network" - # Middleware Headers - - "traefik.http.middlewares.xpeditis-api-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" - - "traefik.http.middlewares.xpeditis-api-headers.headers.customRequestHeaders.X-Forwarded-For=" - - "traefik.http.middlewares.xpeditis-api-headers.headers.customRequestHeaders.X-Real-IP=" - - "traefik.http.middlewares.xpeditis-api-headers.headers.accessControlAllowOriginList=https://app.xpeditis.com,https://www.xpeditis.com" - - "traefik.http.middlewares.xpeditis-api-headers.headers.accessControlAllowMethods=GET,POST,PUT,PATCH,DELETE,OPTIONS" - - "traefik.http.middlewares.xpeditis-api-headers.headers.accessControlAllowHeaders=*" - - "traefik.http.middlewares.xpeditis-api-headers.headers.accessControlMaxAge=3600" - # Rate Limiting - - "traefik.http.middlewares.xpeditis-api-ratelimit.ratelimit.average=100" - - "traefik.http.middlewares.xpeditis-api-ratelimit.ratelimit.burst=200" - - "traefik.http.middlewares.xpeditis-api-ratelimit.ratelimit.period=1m" - # HTTP to HTTPS redirect - - "traefik.http.routers.xpeditis-api-http.rule=Host(`api.xpeditis.com`)" + - "traefik.http.routers.xpeditis-api.middlewares=xpeditis-api-headers" + + # HTTP → HTTPS + - "traefik.http.routers.xpeditis-api-http.rule=Host(`api.preprod.xpeditis.com`)" - "traefik.http.routers.xpeditis-api-http.entrypoints=web" - - "traefik.http.routers.xpeditis-api-http.priority=100" - "traefik.http.routers.xpeditis-api-http.middlewares=xpeditis-redirect" - "traefik.http.routers.xpeditis-api-http.service=xpeditis-api" - depends_on: - - xpeditis-db - - xpeditis-redis - - xpeditis-minio - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:4000/health"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 60s - deploy: - replicas: 2 - placement: - constraints: - - node.role == manager - restart_policy: - condition: on-failure - delay: 10s - max_attempts: 3 - update_config: - parallelism: 1 - delay: 10s - order: start-first - resources: - limits: - cpus: '1.0' - memory: 1G - reservations: - cpus: '0.5' - memory: 512M + + - "traefik.docker.network=traefik_network" # Frontend (Next.js) xpeditis-frontend: - image: xpeditis/frontend:latest + image: rg.fr-par.scw.cloud/weworkstudio/xpeditis-frontend:preprod restart: unless-stopped environment: - NODE_ENV: production - NEXT_PUBLIC_API_URL: https://api.xpeditis.com - NEXT_PUBLIC_WS_URL: wss://api.xpeditis.com + NODE_ENV: preprod + NEXT_PUBLIC_API_URL: https://api.preprod.xpeditis.com + NEXT_PUBLIC_WS_URL: wss://api.preprod.xpeditis.com networks: - traefik_network + labels: - "traefik.enable=true" - # Frontend Routes - - "traefik.http.routers.xpeditis-app.rule=Host(`app.xpeditis.com`) || Host(`www.xpeditis.com`)" + + - "traefik.http.routers.xpeditis-app.rule=Host(`app.preprod.xpeditis.com`) || Host(`www.preprod.xpeditis.com`)" - "traefik.http.routers.xpeditis-app.entrypoints=websecure" - "traefik.http.routers.xpeditis-app.tls=true" - "traefik.http.routers.xpeditis-app.tls.certresolver=letsencrypt" - - "traefik.http.routers.xpeditis-app.priority=50" - "traefik.http.services.xpeditis-app.loadbalancer.server.port=3000" - - "traefik.http.routers.xpeditis-app.middlewares=xpeditis-app-headers" - - "traefik.docker.network=traefik_network" - # Middleware Headers - - "traefik.http.middlewares.xpeditis-app-headers.headers.customRequestHeaders.X-Forwarded-Proto=https" - - "traefik.http.middlewares.xpeditis-app-headers.headers.customRequestHeaders.X-Forwarded-For=" - - "traefik.http.middlewares.xpeditis-app-headers.headers.customRequestHeaders.X-Real-IP=" - # Security Headers - - "traefik.http.middlewares.xpeditis-app-headers.headers.stsSeconds=31536000" - - "traefik.http.middlewares.xpeditis-app-headers.headers.stsIncludeSubdomains=true" - - "traefik.http.middlewares.xpeditis-app-headers.headers.stsPreload=true" - - "traefik.http.middlewares.xpeditis-app-headers.headers.forceSTSHeader=true" - - "traefik.http.middlewares.xpeditis-app-headers.headers.contentTypeNosniff=true" - - "traefik.http.middlewares.xpeditis-app-headers.headers.browserXssFilter=true" - # HTTP to HTTPS redirect - - "traefik.http.routers.xpeditis-app-http.rule=Host(`app.xpeditis.com`) || Host(`www.xpeditis.com`)" + + # HTTP → HTTPS + - "traefik.http.routers.xpeditis-app-http.rule=Host(`app.preprod.xpeditis.com`) || Host(`www.preprod.xpeditis.com`)" - "traefik.http.routers.xpeditis-app-http.entrypoints=web" - - "traefik.http.routers.xpeditis-app-http.priority=50" - "traefik.http.routers.xpeditis-app-http.middlewares=xpeditis-redirect" - "traefik.http.routers.xpeditis-app-http.service=xpeditis-app" - depends_on: - - xpeditis-backend - healthcheck: - test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - deploy: - replicas: 2 - placement: - constraints: - - node.role == manager - restart_policy: - condition: on-failure - delay: 10s - max_attempts: 3 - update_config: - parallelism: 1 - delay: 10s - order: start-first - resources: - limits: - cpus: '0.5' - memory: 512M - reservations: - cpus: '0.25' - memory: 256M + + - "traefik.docker.network=traefik_network" volumes: xpeditis_db_data: - driver: local xpeditis_redis_data: - driver: local xpeditis_minio_data: - driver: local networks: traefik_network: