22 KiB
Estimation des Coûts AWS — Déploiement Production Kubernetes (EKS)
Document de référence — Xpeditis 2.0 Région cible :
us-east-1(oueu-west-1pour conformité RGPD) Base tarifaire : AWS on-demand, mars 2026 MinIO remplacé par S3
Table des matières
- Architecture cible sur EKS
- Inventaire des composants analysés
- Hypothèses par palier d'utilisateurs
- Détail des coûts — 100 utilisateurs
- Détail des coûts — 1 000 utilisateurs
- Détail des coûts — 10 000 utilisateurs
- Tableau récapitulatif
- Économies avec Reserved Instances
- Facteurs de risque et dépassements potentiels
- Recommandations d'optimisation
- Architecture Kubernetes recommandée
1. Architecture cible sur EKS
┌─────────────────────────────────────────────┐
│ AWS VPC (Multi-AZ) │
│ │
Internet ──── Route53 ──┤── CloudFront ──── ALB ──┬── NestJS Pods │
│ │ (EKS NodeGroup) │
│ └── Next.js Pods │
│ │
│ ┌──────────┐ ┌──────────┐ ┌─────────┐ │
│ │ RDS PG15 │ │ElastiCache│ │ S3 │ │
│ │ Multi-AZ │ │ Redis7 │ │ Bucket │ │
│ └──────────┘ └──────────┘ └─────────┘ │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ SES │ │Secrets │ │
│ │ Email │ │Manager │ │
│ └──────────┘ └──────────┘ │
└─────────────────────────────────────────────┘
Services AWS utilisés :
| Service AWS | Remplace / Rôle |
|---|---|
| EKS | Orchestration des containers (backend NestJS + frontend Next.js) |
| RDS PostgreSQL 15 | Base de données principale (18 tables, 29 migrations) |
| ElastiCache Redis 7 | Cache des rate quotes (TTL 15 min), pub/sub WebSocket |
| S3 | Remplace MinIO — PDFs, documents carrier, exports CSV/Excel |
| ALB | Load balancer HTTPS + WebSocket (sticky sessions) |
| CloudFront | CDN pour assets frontend et PDFs publics |
| SES | 10 types d'emails transactionnels (confirmations, invitations, magic links) |
| Secrets Manager | JWT secret, DB passwords, API keys carriers (5 carriers) |
| Route 53 | DNS |
| CloudWatch | Logs (nestjs-pino), métriques, alertes |
| WAF | Protection OWASP (Rate limiting déjà implémenté dans NestJS) |
| NAT Gateway | Accès internet pour les pods (appels APIs carriers) |
2. Inventaire des composants analysés
Backend NestJS (charges identifiées)
Endpoints critiques en charge :
POST /api/v1/rates/search— appelle 5 carriers APIs en parallèle (Maersk, MSC, CMA CGM, Hapag-Lloyd, ONE) avec circuit breaker 5s timeout. C'est le endpoint le plus coûteux en compute.GET /api/v1/rates/csv-search— filtrage in-memory de fichiers CSV uploadés- WebSocket
/notifications— connexions persistantes Socket.IO, pub/sub via Redis
Redis (ElastiCache) :
- Clés :
rate:{origin}:{destination}:{containerType}— TTL 15 minutes - Taux de cache hit estimé : 70–90% pendant les heures de bureau
- Pas de cluster mode nécessaire avant ~500 utilisateurs actifs simultanés
Base de données (RDS) :
- 18 tables avec indexes composites
- Tables à forte croissance :
bookings,audit_logs,notifications,rate_quotes audit_logspeut grossir très vite (~50–200K lignes/mois à 1 000 users)- Extensions PostgreSQL :
pg_trgm(recherche textuelle sur ports)
S3 (remplace MinIO) :
- PDFs booking : 100–500 KB/document, 1 par booking + exports
- Documents carrier : jusqu'à 10 MB/fichier (PDF, images, Excel, CSV)
- Logos d'organisations
- Exports CSV/Excel des bookings
Emails (SES) :
- Vérification email à l'inscription
- Mot de passe oublié / reset
- Email de bienvenue
- Invitation d'utilisateur (token 1h)
- Confirmation de booking avec PDF en pièce jointe
- Demande CSV booking au carrier (magic link)
- Création compte carrier
- Reset password carrier
- Notification nouveaux documents
- Alerte accès documents
Appels APIs externes :
- 5 carriers APIs consultées à chaque rate search non mis en cache
- Latence estimée : 1–3 secondes par carrier
- Volume estimé : 10–30% des searches frappent les APIs (le reste vient du cache Redis)
Frontend Next.js (charges identifiées)
- Mode
standalone— container Docker autonome avec Node.js - SSR / SSG hybride — pages dashboard en CSR, landing page statique
- Bundle gzippé estimé : 200–400 KB (React 19 + Shadcn/ui + TanStack Query)
- Leaflet (cartes), Recharts (graphiques), Framer Motion (animations)
- Images optimisées via
next/imageavec support S3 (**.amazonaws.com)
3. Hypothèses par palier d'utilisateurs
| Paramètre | 100 users | 1 000 users | 10 000 users |
|---|---|---|---|
| Utilisateurs actifs simultanés (pic) | 10–20 | 100–300 | 1 000–3 000 |
| Rate searches / jour | 200–500 | 2 000–8 000 | 20 000–80 000 |
| Bookings créés / mois | 20–50 | 300–800 | 3 000–8 000 |
| Connexions WebSocket simultanées | 10–20 | 100–300 | 1 000–3 000 |
| Emails / mois | 200–500 | 5 000–20 000 | 50 000–200 000 |
| Volume S3 total | 5–20 GB | 100–300 GB | 1–3 TB |
| Upload S3 / mois | 1–5 GB | 20–50 GB | 200–500 GB |
| Trafic sortant APIs carriers / mois | 5–20 GB | 100–300 GB | 1–3 TB |
| Lignes audit_logs cumulées | < 50K | < 1M | < 20M |
4. Détail des coûts — 100 utilisateurs
Phase early-stage / MVP. Architecture sans Multi-AZ sur certains composants pour réduire les coûts.
Compute — EKS
| Ressource | Config | Coût/mois |
|---|---|---|
| EKS Control Plane | 1 cluster | $73 |
| Worker nodes | 2× t3.medium (2 vCPU, 4 GB) — backend + frontend |
$61 |
| Total compute | $134 |
Pods : 2 replicas NestJS (500m CPU / 512Mi chacun) + 1 replica Next.js (250m CPU / 256Mi). HPA désactivé à ce stade.
Base de données — RDS PostgreSQL
| Ressource | Config | Coût/mois |
|---|---|---|
| Instance | db.t4g.medium (2 vCPU, 4 GB) — Single-AZ |
$60 |
| Stockage | 20 GB gp3 | $2 |
| Backups | 7 jours retention | $2 |
| Total RDS | $64 |
Cache — ElastiCache Redis
| Ressource | Config | Coût/mois |
|---|---|---|
| Instance | cache.t4g.micro (1 nœud, 0.5 GB) |
$12 |
Suffisant pour ~10 000 clés rate quotes en cache. Pas de réplication à ce stade.
Stockage — S3
| Ressource | Volume | Coût/mois |
|---|---|---|
| Stockage standard | 10 GB | $0.23 |
| Requêtes PUT/GET | ~50 000/mois | $0.50 |
| Transfert sortant | 5 GB | $0.45 |
| Total S3 | ~$2 |
Réseau
| Ressource | Config | Coût/mois |
|---|---|---|
| ALB | 1 load balancer, ~5 LCU | $22 |
| NAT Gateway | 1 NAT, ~20 GB data processing | $34 |
| CloudFront | Distribution basique, ~5 GB transfert | $5 |
| Total réseau | $61 |
Services managés
| Ressource | Usage | Coût/mois |
|---|---|---|
| SES | ~500 emails (dont ~50 avec PDF joint ~250 KB) | $1 |
| Secrets Manager | 12 secrets | $5 |
| Route 53 | 1 hosted zone + queries | $2 |
| CloudWatch | Logs 5 GB/mois + métriques de base | $15 |
| Total services | $23 |
Total Tier 1 — 100 utilisateurs
| Catégorie | Coût/mois |
|---|---|
| Compute (EKS) | $134 |
| RDS PostgreSQL | $64 |
| ElastiCache Redis | $12 |
| S3 | $2 |
| Réseau (ALB + NAT + CloudFront) | $61 |
| Services (SES + Secrets + R53 + CloudWatch) | $23 |
| TOTAL | ~$296/mois |
| Avec buffer 15% | ~$340/mois |
5. Détail des coûts — 1 000 utilisateurs
Phase croissance. Multi-AZ activé sur RDS, Redis répliqué, autoscaling EKS.
Compute — EKS
| Ressource | Config | Coût/mois |
|---|---|---|
| EKS Control Plane | 1 cluster | $73 |
| Worker nodes | 3× t3.xlarge (4 vCPU, 16 GB) — autoscaling 3–6 nodes |
$362 |
| Total compute | $435 |
Pods : 4 replicas NestJS (1 CPU / 1 GB chacun) + 2 replicas Next.js. HPA activé (CPU > 70%).
Base de données — RDS PostgreSQL
| Ressource | Config | Coût/mois |
|---|---|---|
| Instance | db.r6g.large (2 vCPU, 16 GB) — Multi-AZ |
$350 |
| Stockage | 100 GB gp3 | $10 |
| RDS Proxy | Connection pooling (critique pour NestJS) | $36 |
| Backups | 30 jours retention | $20 |
| Total RDS | $416 |
RDS Proxy devient essentiel à partir de ~50 connexions concurrentes pour éviter les
too many connections.
Cache — ElastiCache Redis
| Ressource | Config | Coût/mois |
|---|---|---|
| Instance | cache.r6g.large (2 nœuds, 13 GB) — réplication activée |
$242 |
La réplication est nécessaire pour le pub/sub WebSocket multi-pods (Socket.IO scale-out).
Stockage — S3
| Ressource | Volume | Coût/mois |
|---|---|---|
| Stockage standard | 150 GB | $3.45 |
| Stockage Intelligent-Tiering (archives) | 50 GB | $2.50 |
| Requêtes PUT/GET | ~500 000/mois | $3 |
| Transfert sortant | 50 GB | $4.50 |
| Total S3 | ~$13 |
Réseau
| Ressource | Config | Coût/mois |
|---|---|---|
| ALB | 1 load balancer, ~50 LCU | $38 |
| NAT Gateway | 2 NATs (HA Multi-AZ), ~150 GB data | $73 |
| CloudFront | ~50 GB transfert (assets + PDFs) | $25 |
| Total réseau | $136 |
Services managés
| Ressource | Usage | Coût/mois |
|---|---|---|
| SES | ~15 000 emails/mois | $1.50 |
| SES — pièces jointes PDF | ~300 bookings × 250 KB | $0.10 |
| Secrets Manager | 15 secrets | $6 |
| Route 53 | 1 zone + queries | $3 |
| CloudWatch | Logs 20 GB/mois + métriques + dashboards | $50 |
| WAF | 1 WebACL, 5 rules, ~5M requêtes/mois | $12 |
| Total services | $73 |
Total Tier 2 — 1 000 utilisateurs
| Catégorie | Coût/mois |
|---|---|
| Compute (EKS) | $435 |
| RDS PostgreSQL (Multi-AZ + Proxy) | $416 |
| ElastiCache Redis (répliqué) | $242 |
| S3 | $13 |
| Réseau (ALB + NAT + CloudFront) | $136 |
| Services (SES + Secrets + R53 + CW + WAF) | $73 |
| TOTAL | ~$1 315/mois |
| Avec buffer 15% | ~$1 512/mois |
6. Détail des coûts — 10 000 utilisateurs
Phase scale. Read replica RDS, Redis cluster mode, autoscaling agressif, WAF renforcé.
Compute — EKS
| Ressource | Config | Coût/mois |
|---|---|---|
| EKS Control Plane | 1 cluster | $73 |
| Worker nodes — backend | 4× m6i.xlarge (4 vCPU, 16 GB) — autoscaling 4–12 |
$560 |
| Worker nodes — frontend | 2× m6i.large (2 vCPU, 8 GB) — autoscaling 2–6 |
$140 |
| Total compute | $773 |
Pods NestJS : 8–15 replicas (1.5 CPU / 1.5 GB chacun). HPA + KEDA si adoption de SQS. Pods Next.js : 4–8 replicas (500m CPU / 512 Mi chacun).
Base de données — RDS PostgreSQL
| Ressource | Config | Coût/mois |
|---|---|---|
| Instance primaire | db.r6g.2xlarge (8 vCPU, 64 GB) — Multi-AZ |
$1 402 |
| Read Replica | db.r6g.xlarge (analytics + audit queries) |
$350 |
| Stockage | 1 TB gp3 (SSD) | $100 |
| RDS Proxy | Haute disponibilité | $100 |
| Backups | 30 jours + point-in-time recovery | $100 |
| Total RDS | $2 052 |
À 10 000 users,
audit_logspeut dépasser 10M lignes. Envisager un archivage vers S3/Athena après 90 jours.
Cache — ElastiCache Redis
| Ressource | Config | Coût/mois |
|---|---|---|
| Cluster mode | 3 shards × 2 nœuds cache.r6g.large (13 GB/shard) |
$1 452 |
Cluster mode nécessaire pour distribuer les ~100 000+ clés rate quotes et supporter le pub/sub à grande échelle.
Stockage — S3
| Ressource | Volume | Coût/mois |
|---|---|---|
| Stockage Standard | 500 GB (documents actifs < 30 jours) | $11.50 |
| Stockage Intelligent-Tiering | 1 TB (documents anciens) | $23 |
| Glacier Instant Retrieval | 2 TB (archives > 6 mois) | $8 |
| Requêtes PUT/GET | ~5M/mois | $20 |
| Transfert sortant S3 | 200 GB (via CloudFront réduit les coûts) | $9 |
| Total S3 | ~$72 |
Réseau
| Ressource | Config | Coût/mois |
|---|---|---|
| ALB | 2 load balancers (backend + frontend), ~200 LCU | $110 |
| NAT Gateway | 2 NATs, ~1 TB appels carriers + Redis | $111 |
| CloudFront | ~500 GB transfert (assets + PDFs + exports) | $125 |
| Total réseau | $346 |
Services managés
| Ressource | Usage | Coût/mois |
|---|---|---|
| SES | ~120 000 emails/mois | $12 |
| SES — pièces jointes PDF | ~5 000 bookings × 300 KB | $1.80 |
| Secrets Manager | 20 secrets + 2M API calls/mois | $18 |
| Route 53 | 2 zones (prod + staging), traffic routing | $10 |
| CloudWatch | Logs 100 GB/mois + métriques + Container Insights | $200 |
| WAF + Shield Standard | WebACL, 10 rules, ~50M requêtes/mois, DDoS basique | $65 |
| KMS | Encryption at rest RDS/S3, rotation clés | $10 |
| Total services | $317 |
Total Tier 3 — 10 000 utilisateurs
| Catégorie | Coût/mois |
|---|---|
| Compute (EKS) | $773 |
| RDS PostgreSQL (Multi-AZ + Replica + Proxy) | $2 052 |
| ElastiCache Redis (cluster mode) | $1 452 |
| S3 (avec tiering) | $72 |
| Réseau (ALB + NAT + CloudFront) | $346 |
| Services (SES + Secrets + R53 + CW + WAF + KMS) | $317 |
| TOTAL | ~$5 012/mois |
| Avec buffer 15% | ~$5 764/mois |
7. Tableau récapitulatif
| Composant | 100 users | 1 000 users | 10 000 users |
|---|---|---|---|
| EKS (Control Plane + Nodes) | $134 | $435 | $773 |
| RDS PostgreSQL | $64 | $416 | $2 052 |
| ElastiCache Redis | $12 | $242 | $1 452 |
| S3 | $2 | $13 | $72 |
| Réseau (ALB + NAT + CDN) | $61 | $136 | $346 |
| Services managés | $23 | $73 | $317 |
| TOTAL (on-demand) | $296 | $1 315 | $5 012 |
| TOTAL avec buffer 15% | ~$340 | ~$1 512 | ~$5 764 |
Note hors scope : Stripe facture 2.9% + $0.30 par transaction. Pour 500 transactions/mois à $500 chacune, cela représente ~$7 400/mois de frais Stripe — à prendre en compte dans la marge business, pas dans l'infra.
8. Économies avec Reserved Instances
Engager 1 ou 3 ans sur les ressources stables (RDS, ElastiCache, nœuds EKS de base) permet des économies significatives.
1 an — Savings Plans
| Composant | Coût on-demand | Après 1 an RI (~35% réduction) |
|---|---|---|
| RDS (1 000 users) | $416 | ~$270 |
| ElastiCache (1 000 users) | $242 | ~$157 |
| EC2 workers EKS (1 000 users) | $362 | ~$235 |
| Économie mensuelle | ~$358/mois |
Impact par palier avec Reserved Instances 1 an
| Palier | On-demand | Avec RI 1 an | Économie annuelle |
|---|---|---|---|
| 100 users | $296 | ~$220 | ~$912 |
| 1 000 users | $1 315 | ~$950 | ~$4 380 |
| 10 000 users | $5 012 | ~$3 600 | ~$16 944 |
9. Facteurs de risque et dépassements potentiels
🔴 Risque élevé — Appels APIs carriers
Chaque POST /rates/search sans cache Redis déclenche 5 appels HTTP externes en parallèle.
À 1 000 users avec 30% de cache miss → ~2 400 appels/heure vers les carriers.
Impact NAT Gateway : transfert data $0.045/GB. Si chaque réponse carrier fait 10 KB → ~100 GB/mois → $4.50.
Si les réponses sont plus volumineuses (50 KB+) ou si le cache miss monte → coût × 5 à × 10.
Mitigation : Ajuster le TTL Redis (actuellement 15 min) à 30–60 min pour les routes peu demandées.
🔴 Risque élevé — audit_logs à 10 000 users
À 10 000 users, audit_logs peut atteindre 50–200M lignes/an (toutes actions loggées).
RDS db.r6g.2xlarge avec 1 TB de stockage sera rapidement saturé.
Mitigation : Mettre en place un archivage automatique des logs > 90 jours vers S3 + Athena pour les requêtes analytiques.
🟡 Risque moyen — WebSocket à grande échelle
Socket.IO avec Redis adapter fonctionne bien jusqu'à ~2 000 connexions simultanées sur un cache.r6g.large. Au-delà, envisager de passer à Redis Cluster mode ou à une gateway WebSocket dédiée.
🟡 Risque moyen — PDFs avec pièces jointes emails (SES)
Les booking confirmations envoient le PDF en base64 dans le corps de l'email (détecté dans le code email service). Pour 5 000 bookings/mois à 300 KB/PDF → 1.5 GB de data SES/mois → $0.18/mois en plus des emails. À grande échelle, préférer un lien S3 signé dans l'email plutôt qu'une pièce jointe.
🟡 Risque moyen — ElastiCache sous-dimensionné
Le nombre de clés Redis peut exploser si les recherches sont très diversifiées (nombreuses combinaisons origin/destination/containerType).
Monitorer cache.CurrItems et BytesUsedForCache dans CloudWatch dès le démarrage.
🟢 Risque faible — S3
Les coûts S3 restent maîtrisés avec les politiques de cycle de vie (Intelligent-Tiering + Glacier). La migration MinIO → S3 est transparente (l'app utilise déjà le SDK AWS S3 v3).
10. Recommandations d'optimisation
Priorité haute (impact fort, faible effort)
-
S3 Lifecycle Policies dès le J1
- Documents > 30 jours → Intelligent-Tiering
- Documents > 180 jours → Glacier Instant Retrieval
- Économie estimée : 50–70% sur les coûts de stockage long terme
-
RDS Proxy activé dès 1 000 users
- NestJS ouvre N connexions par pod × N pods → sans proxy, RDS sature
db.r6g.largesupporte ~150 connexions max, 10 pods × 10 connexions = limite atteinte
-
CloudFront pour tous les assets S3 publics
- Élimine le transfert sortant S3 (×8 fois moins cher via CloudFront)
- Mettre en cache les PDFs de booking (signé URL → CloudFront signed URL)
-
Reserved Instances 1 an sur RDS + ElastiCache
- Ces deux services représentent 50–60% de la facture à 1 000+ users
- Le ROI est atteint dès le premier mois comparé à l'on-demand
Priorité moyenne
-
Archivage audit_logs vers S3 + Athena
- Créer un job cron mensuel qui exporte les logs > 90 jours en Parquet vers S3
- Requêtes analytiques via Athena ($5 par TB scanné)
- Libère l'espace RDS et maintient les performances des indexes
-
SQS + Lambda pour la génération de PDFs et l'envoi d'emails
- Actuellement synchrone → bloque le thread NestJS
- Découpler : POST /bookings → enfile en SQS → Lambda génère PDF + envoie email
- Réduit les besoins CPU des pods NestJS (~20% de réduction possible)
-
Lien S3 signé dans les emails plutôt que pièce jointe
- Remplacer le PDF base64 dans SES par un lien CloudFront signé (1h expiry)
- Réduit la taille des emails de 60–70% et évite les filtres anti-spam
Priorité basse
-
Fargate Spot pour les pods non-critiques
- Workers de génération PDF/export peuvent tourner sur Fargate Spot (70% moins cher)
-
KEDA (Kubernetes Event-Driven Autoscaling)
- Scaler les pods NestJS selon la profondeur de la file SQS plutôt que le CPU
11. Architecture Kubernetes recommandée
Namespaces
xpeditis-prod
├── backend # NestJS pods
├── frontend # Next.js pods
└── monitoring # Prometheus + Grafana (optionnel)
Sizing des pods par palier
Backend NestJS
| Palier | Replicas (base) | Replicas (max HPA) | CPU request/limit | RAM request/limit |
|---|---|---|---|---|
| 100 users | 2 | 3 | 500m / 1500m | 512Mi / 1Gi |
| 1 000 users | 4 | 8 | 750m / 2000m | 768Mi / 1.5Gi |
| 10 000 users | 8 | 20 | 1000m / 3000m | 1Gi / 2Gi |
Frontend Next.js (standalone)
| Palier | Replicas (base) | Replicas (max HPA) | CPU request/limit | RAM request/limit |
|---|---|---|---|---|
| 100 users | 1 | 2 | 250m / 1000m | 256Mi / 512Mi |
| 1 000 users | 2 | 4 | 500m / 1500m | 512Mi / 1Gi |
| 10 000 users | 3 | 8 | 750m / 2000m | 512Mi / 1Gi |
Variables d'environnement Kubernetes (Secrets)
À stocker dans AWS Secrets Manager et monter via External Secrets Operator :
DATABASE_URL→ RDS connection string avec RDS Proxy endpointREDIS_HOST/REDIS_PASSWORD→ ElastiCache primary endpointJWT_SECRET→ rotation automatique mensuelle recommandéeAWS_S3_BUCKET→ remplaceMINIO_ENDPOINT/MINIO_ACCESS_KEY/MINIO_SECRET_KEYSTRIPE_SECRET_KEY/STRIPE_WEBHOOK_SECRET- API keys × 5 carriers (Maersk, MSC, CMA CGM, Hapag-Lloyd, ONE)
SMTP_HOST→ SES SMTP endpoint + credentials
Ingress (ALB Ingress Controller)
# Règles d'ingress recommandées
/api/* → backend service (port 4000)
/socket.io/* → backend service (sticky sessions activées)
/* → frontend service (port 3000)
Le WebSocket Socket.IO nécessite
alb.ingress.kubernetes.io/target-group-attributes: stickiness.enabled=true
Résumé exécutif
| 100 users | 1 000 users | 10 000 users | |
|---|---|---|---|
| Coût mensuel estimé | ~$340 | ~$1 500 | ~$5 800 |
| Coût annuel | ~$4 080 | ~$18 000 | ~$69 600 |
| Avec RI 1 an | ~$2 640 | ~$11 400 | ~$43 200 |
| Poste dominant | Compute + Réseau | RDS Multi-AZ | RDS + Redis |
| Principal risque | Sur-dimensionnement | Connexions DB | audit_logs volume |
Les prix sont indicatifs en us-east-1 (on-demand, mars 2026).
eu-west-1(Paris :eu-west-3) est ~5–10% plus cher. Ces estimations excluent : les frais Stripe (2.9% + $0.30/transaction), les licences SaaS tierces éventuelles, et les coûts de développement/opération.