Migration Heroku vers AWS : Comment Réduire vos Coûts de 30 à 70%
La migration de Heroku vers AWS est devenue incontournable pour les entreprises en croissance. Heroku, bien que pratique pour prototyper rapidement, devient rapidement très coûteux à l’échelle. Cette migration peut générer entre 30% et 70% d’économies tout en offrant plus de contrôle et de flexibilité.
Cet article détaille le processus complet de migration basé sur un cas réel : Monnier, plateforme e-commerce qui a réduit ses coûts infrastructure de 72% en migrant vers AWS Elastic Beanstalk.
Pourquoi Migrer de Heroku vers AWS ?
Le Coût Croissant de Heroku
Heroku fonctionne avec une tarification par “dyno” (conteneur applicatif) qui devient rapidement prohibitive :
Exemple réel Monnier :
Heroku : - 1x Basic dyno (Front) : 7€/mois - 1x Standard-2X dyno (Strapi Front) : 50€/mois - 2x Performance-M dynos (Workers) : 500€/mois - Total : 557€/mois
AWS Elastic Beanstalk (architecture réelle déployée) : - t3.medium (Front) : 33.93€/mois - c5.large (Strapi) : 71.42€/mois - c5.large (Worker) : 142.85€/mois - t3.medium Spot (Traitement photos) : 11.31€/mois - Total : 259.51€/mois
Économie réelle : -53.4% (297€ économisés/mois, soit 3 570€/an)
Et avec un dimensionnement optimal + Savings Plans : jusqu’à -89.8% d’économies possibles.
Les Limites Techniques de Heroku
Au-delà du coût, Heroku impose des contraintes :
- Scaling limité : Impossible de scaler certains composants indépendamment
- Vendor lock-in : Dépendance aux add-ons propriétaires Heroku
- Visibilité réduite : Métriques et logs limités sans add-ons coûteux
- Performance : Réseau partagé entre tenants, latence variable
- Personnalisation : Architecture figée, impossible d’optimiser finement
Cas Réel : Migration Monnier (E-commerce)
Contexte du Projet
Entreprise : Monnier, plateforme e-commerce mode Infrastructure Heroku : Architecture multi-services avec dynos Performance Objectif : Réduire drastiquement les coûts tout en améliorant les performances
Architecture Avant Migration
Stack Heroku : - 1x Basic dyno (Front Nuxt - 1 CPU, 0.5GB RAM) : 7€/mois - 1x Standard-2X dyno (Strapi Front - 2 CPU, 1GB RAM) : 50€/mois - 1x Performance-M dyno (Strapi Worker - 12 CPU, 2.5GB RAM) : 250€/mois - 1x Performance-M dyno (Traitement photos - 12 CPU, 2.5GB RAM) : 250€/mois - PostgreSQL déjà hébergé sur AWS RDS - Redis Premium-2
Coût mensuel Heroku : 557€/mois (6 684€/an)
Stratégie de Migration
Phase 1 : Analyse et Dimensionnement
Audit de l’existant :
# Analyse des métriques Heroku
heroku ps --app monnier-prod
heroku redis:info --app monnier-prod
Questions clés : - Quelles sont les ressources réellement consommées (CPU, RAM, I/O) ? - Quels pics de charge l’application subit-elle ? - Quelles dépendances aux add-ons Heroku spécifiques ? - Quelle partie du code dépend de la plateforme Heroku ?
Résultat Monnier : - Sur-provisionnement massif détecté : Performance-M (12 CPU, 2.5GB RAM) alors que t3.medium (2 CPU, 4GB RAM) suffit largement - CPU réel : 20-30% des capacités Heroku sur les dynos Performance-M - PostgreSQL : Déjà sur AWS RDS (aucune migration nécessaire) - Redis : Cache applicatif - Front Nuxt : Basic dyno largement sur-dimensionné pour un front statique
Phase 2 : Choix de la Stack AWS
Plusieurs options pour migrer depuis Heroku :
Option 1 : AWS Elastic Beanstalk (choisi par Monnier) - ✅ Service managé similaire à Heroku - ✅ Transition en douceur pour les équipes - ✅ Load balancing et auto-scaling intégrés - ✅ Déploiement simple via CLI ou CI/CD - ⚠️ Moins flexible que Kubernetes
Option 2 : Amazon ECS/Fargate - ✅ Conteneurisation complète - ✅ Scaling granulaire - ✅ Intégration parfaite avec l’écosystème AWS - ⚠️ Plus complexe à configurer
Option 3 : Amazon EKS (Kubernetes) - ✅ Maximum de flexibilité et portabilité - ✅ GitOps avec ArgoCD possible - ✅ Multi-cloud ready - ⚠️ Complexité opérationnelle élevée - ⚠️ Overhead de gestion du cluster
Pourquoi Elastic Beanstalk pour Monnier ? - Équipe dev habituée à Heroku, transition progressive souhaitée - Pas besoin de la complexité Kubernetes à court terme - Time-to-market prioritaire - Service managé AWS réduit la charge opérationnelle
Phase 3 : Migration de l’Infrastructure
1. Configuration Base de Données (Déjà sur AWS RDS)
Dans le cas de Monnier, PostgreSQL était déjà hébergé sur AWS RDS, ce qui simplifie considérablement la migration. Seule action nécessaire : ajuster les security groups.
# Ajouter règle security group pour Elastic Beanstalk
aws ec2 authorize-security-group-ingress \
--group-id sg-xxxxx-rds \
--protocol tcp \
--port 5432 \
--source-group sg-yyyyy-beanstalk
Avantage majeur : Pas de migration de données, pas de downtime PostgreSQL, connexion directe depuis les nouvelles instances Elastic Beanstalk.
Si votre base était sur Heroku Postgres, voici le process complet :
Migration PostgreSQL Heroku → AWS RDS
# Export depuis Heroku Postgres
heroku pg:backups:capture --app monnier-prod
heroku pg:backups:download --app monnier-prod
# Créer instance RDS
aws rds create-db-instance \
--db-instance-identifier monnier-prod \
--db-instance-class db.m5.large \
--engine postgres \
--engine-version 15.4 \
--allocated-storage 100 \
--storage-encrypted \
--backup-retention-period 7 \
--multi-az
# Restauration
pg_restore -h monnier-prod.xxxx.rds.amazonaws.com \
-U postgres -d monnier latest.dump
Points d’attention : - Choisir la même version PostgreSQL - Activer Multi-AZ pour haute disponibilité - Tester les performances en charge avant cutover
2. Migration Redis
# ElastiCache Redis cluster
aws elasticache create-cache-cluster \
--cache-cluster-id monnier-redis \
--cache-node-type cache.m5.large \
--engine redis \
--num-cache-nodes 1 \
--engine-version 7.0
# Export/Import des données si nécessaire
redis-cli --rdb /tmp/dump.rdb
3. Configuration Elastic Beanstalk
Création de l’application :
eb init monnier-api --platform "Node.js 18" --region eu-west-1
eb create monnier-prod \
--instance-type m5.large \
--scale 3 \
--envvars DATABASE_URL=$DB_URL,REDIS_URL=$REDIS_URL
Configuration auto-scaling :
# .ebextensions/autoscaling.config
option_settings:
aws:autoscaling:asg:
MinSize: 3
MaxSize: 12
aws:autoscaling:trigger:
MeasureName: CPUUtilization
Statistic: Average
Unit: Percent
UpperThreshold: 70
LowerThreshold: 30
4. Adaptation du Code Applicatif
Variables d’environnement :
// Avant (Heroku)
const dbUrl = process.env.DATABASE_URL; // Format Heroku spécifique
// Après (AWS compatible)
const dbConfig = {
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
ssl: { rejectUnauthorized: false }
};
Logs :
// Avant : logs Heroku automatiques
console.log('Request processed');
// Après : CloudWatch Logs
const winston = require('winston');
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new winston.transports.File({ filename: '/var/log/app.log' })
]
});
Phase 4 : Pipeline CI/CD
GitLab CI pour déploiement Elastic Beanstalk :
# .gitlab-ci.yml
stages:
- build
- deploy
build:
stage: build
script:
- npm ci
- npm run build
- zip -r application.zip . -x "*.git*"
artifacts:
paths:
- application.zip
deploy_production:
stage: deploy
only:
- main
script:
# Upload vers S3
- aws s3 cp application.zip s3://monnier-deployments/app-${CI_COMMIT_SHA}.zip
# Créer nouvelle version Elastic Beanstalk
- |
aws elasticbeanstalk create-application-version \
--application-name monnier-api \
--version-label ${CI_COMMIT_SHA} \
--source-bundle S3Bucket=monnier-deployments,S3Key=app-${CI_COMMIT_SHA}.zip
# Déployer
- |
aws elasticbeanstalk update-environment \
--environment-name monnier-prod \
--version-label ${CI_COMMIT_SHA}
Rollback facile :
# Lister les versions
aws elasticbeanstalk describe-application-versions \
--application-name monnier-api
# Rollback vers version précédente
aws elasticbeanstalk update-environment \
--environment-name monnier-prod \
--version-label <version-precedente>
Phase 5 : Migration Progressive (Blue-Green)
Stratégie de cutover sans downtime :
Infrastructure en parallèle :
- Heroku continue de tourner
- AWS Elastic Beanstalk configuré et testé
- Bases de données synchronisées (réplication)
Tests de charge :
# Simulation charge avec k6 k6 run --vus 100 --duration 30m load-test.jsMigration DNS progressive :
# Route 53 weighted routing aws route53 change-resource-record-sets \ --hosted-zone-id Z123456 \ --change-batch '{ "Changes": [{ "Action": "CREATE", "ResourceRecordSet": { "Name": "api.monnier.com", "Type": "A", "SetIdentifier": "AWS", "Weight": 10, "AliasTarget": { "HostedZoneId": "Z123", "DNSName": "monnier-prod.elasticbeanstalk.com" } } }] }'
Bascule progressive :
- Jour 1 : 10% trafic AWS, 90% Heroku
- Jour 3 : 50% AWS, 50% Heroku
- Jour 5 : 100% AWS
Surveillance étroite :
# CloudWatch metrics aws cloudwatch get-metric-statistics \ --namespace AWS/ElasticBeanstalk \ --metric-name CPUUtilization \ --dimensions Name=EnvironmentName,Value=monnier-prod \ --start-time 2025-01-01T00:00:00Z \ --end-time 2025-01-02T00:00:00Z \ --period 300 \ --statistics AveragePhase 6 : Optimisation Post-Migration
Une fois la migration validée, optimisations pour réduire encore les coûts :
Right-Sizing
Analyse des métriques : - CPU moyen : 35% → instance sur-dimensionnée - RAM : 60% utilisée → marge correcte - I/O disque : faible → EBS gp3 suffit (vs io2) Ajustements :
# Passer de m5.large à m5.medium pour certains workers eb scale 3 --instance-type m5.medium monnier-workers
Résultat Monnier : 15% d’économies supplémentaires via right-sizing.
Spot Instances pour Workers Non-Critiques
# .ebextensions/spot-instances.config
option_settings:
aws:ec2:instances:
SpotFleetOnDemandBase: 1
SpotFleetOnDemandAboveBasePercentage: 0
SpotMaxPrice: 0.05
Économies : 60-70% sur les workers batch/background.
Reserved Instances / Savings Plans
Pour les instances stables :
# Achat Reserved Instance 1 an
aws ec2 purchase-reserved-instances-offering \
--reserved-instances-offering-id xxxxx \
--instance-count 3
Économies : 30-40% sur instances on-demand.
Optimisation Base de Données
RDS Performance Insights :
aws rds describe-db-instances \
--db-instance-identifier monnier-prod \
--query 'DBInstances[0].PerformanceInsightsEnabled'
Actions : - Identifier les requêtes lentes (>100ms) - Ajouter indexes manquants - Optimiser les requêtes N+1
Résultat : Possibilité de downgrade RDS de db.m5.large → db.m5.medium.
Résultats Monnier
Économies Réalisées
Coûts mensuels détaillés :
| Service | Instance Heroku | Coût Heroku | Instance AWS proposée | Coût AWS (on-demand) | Coût AWS (Savings Plans) | Instance réelle | Coût réel |
|---|---|---|---|---|---|---|---|
| Front Nuxt | Basic (1 CPU, 0.5GB) | 7€ | t3.nano (2 CPU, 0.5GB) | 4.39€ | 2.70€ | t3.medium | 33.93€ |
| Strapi Front | Standard-2X (2 CPU, 1GB) | 50€ | t3.small (2 CPU, 2GB) | 17.56€ | 10.80€ | c5.large | 71.42€ |
| Strapi Worker | Performance-M (12 CPU, 2.5GB) | 250€ | t3.medium (2 CPU, 4GB) | 35.12€ | 21.70€ | c5.large | 142.85€ |
| Traitement photos | Performance-M (12 CPU, 2.5GB) | 250€ | t3.medium (2 CPU, 4GB) | 35.12€ | 21.70€ | t3.medium Spot | 11.31€ |
| Base de données RDS | (déjà AWS) | — | — | — | — | — | — |
| TOTAL | 557€ | 92.19€ | 56.90€ | 259.51€ | |||
| TOTAL ANNUEL | 6 684€ | 1 106€ | 682.80€ | 3 114€ |
Résultats : - Économie avec dimensionnement optimal : 557€ → 56.90€/mois = -89.8% (500€ économisés/mois) - Infrastructure réelle déployée : 557€ → 259.51€/mois = -53.4% (297€ économisés/mois) - Économie annuelle réelle : 3 570€
Note importante : L’infrastructure réelle utilise des instances plus puissantes (t3.medium au lieu de t3.nano pour le front, c5.large au lieu de t3.small/medium) pour garantir de la marge. Malgré ce sur-provisionnement AWS, l’économie reste de 53% par rapport à Heroku.
Optimisation maximale possible : En appliquant le dimensionnement optimal + Savings Plans, l’économie atteindrait 89.8% (de 557€ à 56.90€/mois).
Détail de l’Optimisation Spot Instances
Traitement photos : Worker non-critique migré vers t3.medium Spot : - Coût on-demand : 35.12€/mois - Coût Spot : 11.31€/mois - Économie : -67.8% sur ce composant
Les Spot Instances sont parfaites pour les workloads tolérants aux interruptions (traitement batch, workers non temps-réel).
Améliorations Techniques
Performance : - Temps de réponse : comparable voire meilleur (même région AWS pour compute + RDS) - Déploiements : automatisés via GitLab CI vers S3 + Elastic Beanstalk - Rollback : instantané (versions Elastic Beanstalk)
Contrôle : - Visibilité complète : CloudWatch métriques détaillées par instance - Logs centralisés : CloudWatch Logs Insights - Sécurité : VPC privé, security groups granulaires entre services
Flexibilité : - Spot Instances pour worker traitement photos : -67.8% sur ce composant - Scaling indépendant par service - Possibilité d’optimiser encore (Savings Plans : -38% supplémentaires)
Détail du Sur-Provisionnement Heroku Détecté
Traitement photos : - Heroku : Performance-M (12 CPU, 2.5GB RAM) à 250€/mois - AWS optimal : t3.medium (2 CPU, 4GB RAM) à 35.12€/mois - Sur-provisionnement : 6x plus de CPU que nécessaire
Ce sur-dimensionnement est typique sur Heroku : les dynos imposent des paliers fixes (Basic → Standard → Performance) sans granularité, forçant à payer pour des ressources inutilisées.
Checklist Migration Heroku → AWS
Pré-Migration
- [ ] Audit des ressources Heroku réellement consommées (CPU, RAM, I/O)
- [ ] Identification des add-ons Heroku et équivalents AWS
- [ ] Analyse des dépendances code au runtime Heroku
- [ ] Estimation budget AWS (calculateur AWS Pricing)
- [ ] Choix de la stack AWS (Beanstalk, ECS, EKS)
Migration Infrastructure
- [ ] Création VPC AWS avec subnets publics/privés (si nécessaire)
- [ ] Migration base de données vers RDS (si pas déjà sur AWS)
- [ ] Ajustement security groups pour connexion RDS ↔ Compute
- [ ] Migration Redis vers ElastiCache
- [ ] Configuration Elastic Beanstalk / ECS / EKS
- [ ] Setup load balancer + auto-scaling
- [ ] Configuration CloudWatch monitoring
Migration Applicative
- [ ] Adaptation variables d’environnement
- [ ] Modification configuration logs (CloudWatch)
- [ ] Tests de l’application sur AWS (staging)
- [ ] Configuration secrets (AWS Secrets Manager)
- [ ] Tests de charge (k6, Locust, JMeter)
CI/CD
- [ ] Pipeline GitLab/GitHub vers AWS
- [ ] Déploiement automatisé (S3 + Elastic Beanstalk CLI)
- [ ] Tests automatisés pré-déploiement
- [ ] Rollback automatique en cas d’erreur
Cutover
- [ ] Synchronisation bases de données Heroku → AWS (si applicable)
- [ ] Vérification connectivité RDS depuis nouvelles instances
- [ ] Migration DNS progressive (Route 53 weighted routing)
- [ ] Monitoring étroit pendant 72h
- [ ] Validation métriques performance
- [ ] Désactivation Heroku après validation complète
Post-Migration
- [ ] Right-sizing instances (analyse 2 semaines de métriques)
- [ ] Activation Spot Instances pour workloads non-critiques
- [ ] Achat Reserved Instances / Savings Plans
- [ ] Optimisation requêtes base de données
- [ ] Configuration alertes CloudWatch
Alternatives à Elastic Beanstalk
Amazon ECS + Fargate
Avantages : - Conteneurisation complète (Docker) - Pas de gestion de serveurs (serverless containers) - Scaling granulaire par service
Inconvénients : - Courbe d’apprentissage plus raide - Configuration initiale plus longue
Quand choisir ? : Application déjà conteneurisée, besoin de scaling fin par microservice.
Amazon EKS (Kubernetes)
Avantages : - Portabilité multi-cloud - Écosystème riche (Helm, ArgoCD, Istio) - GitOps natif avec ArgoCD
Inconvénients : - Complexité opérationnelle élevée - Coût du control plane : 72€/mois - Expertise Kubernetes requise
Quand choisir ? : Architecture microservices (10+ services), équipe DevOps expérimentée, stratégie multi-cloud.
Exemple migration vers EKS :
# Deployment Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: monnier-api
spec:
replicas: 3
selector:
matchLabels:
app: monnier-api
template:
metadata:
labels:
app: monnier-api
spec:
containers:
- name: api
image: monnier/api:latest
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 1000m
memory: 2Gi
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-credentials
key: url
Erreurs à Éviter
1. Sous-Estimer la Préparation
❌ Erreur : Migrer sans analyser les métriques Heroku réelles ✅ Solution : Auditer 2-4 semaines de métriques CPU/RAM/I/O avant dimensionnement AWS
2. Big Bang Migration
❌ Erreur : Couper Heroku et basculer 100% sur AWS d’un coup ✅ Solution : Migration progressive (weighted routing DNS), rollback facile
3. Négliger les Tests de Charge
❌ Erreur : Valider uniquement en environnement de dev ✅ Solution : Tests de charge réalistes (k6) simulant trafic production
4. Oublier les Coûts Cachés AWS
❌ Erreur : Calculer uniquement EC2 + RDS ✅ Solution : Inclure data transfer, EBS, snapshots, CloudWatch logs
5. Sur-Dimensionner Dès le Début
❌ Erreur : Prendre des instances larges “au cas où” ✅ Solution : Commencer conservateur, right-size après 2 semaines de métriques
Combien de Temps pour Migrer ?
Timeline réaliste pour une application moyenne :
- Semaine 1-2 : Audit, analyse, choix architecture AWS
- Semaine 3-4 : Setup infrastructure AWS (staging)
- Semaine 5-6 : Adaptation code, tests, CI/CD
- Semaine 7 : Migration bases de données (si nécessaire), tests de charge
- Semaine 8 : Cutover progressif, surveillance
Total : 6-8 semaines pour une migration maîtrisée.
Cas Monnier : Migration accélérée grâce à PostgreSQL déjà sur AWS. Seule la partie compute Heroku → Elastic Beanstalk a nécessité migration et tests.
Conclusion
La migration Heroku vers AWS peut générer 50 à 90% d’économies tout en améliorant performances, contrôle et flexibilité. Le cas Monnier démontre 53% d’économies immédiates (557€ → 259€/mois) avec possibilité d’atteindre 90% via optimisations (Savings Plans, right-sizing).
Points clés : 1. Détecter le sur-provisionnement Heroku : Les paliers fixes (Basic, Standard, Performance) forcent à payer pour des ressources inutilisées 2. Analyser avant d’agir : métriques Heroku réelles, pas d’estimations 3. Choisir la bonne stack AWS : Beanstalk (simple), ECS (conteneurs), EKS (microservices) 4. Optimiser intelligemment : Spot Instances pour workloads non-critiques, Savings Plans pour prévisible
Résultat Monnier : - 557€/mois sur Heroku → 259€/mois sur AWS = -53% avec marge confortable - Optimisation maximale possible : 56.90€/mois = -90%
Votre application coûte >500€/mois sur Heroku ? Une migration AWS bien menée peut réduire cette facture de 50 à 90%.
Le passage à AWS ne se limite pas aux économies : c’est aussi reprendre le contrôle de votre infrastructure, gagner en flexibilité et préparer votre scaling futur sans les contraintes d’un PaaS propriétaire.
Points clés à retenir
- ✓ Migration Heroku vers AWS : économies de 50-90% sur coûts infrastructure
- ✓ Cas Monnier : 53% de réduction immédiate (557€ → 259€/mois) avec Elastic Beanstalk
- ✓ Sur-provisionnement Heroku détecté : Performance-M (12 CPU) alors que 2 CPU suffisent
- ✓ Spot Instances pour traitement photos : -67.8% (35€ → 11€/mois)
- ✓ Optimisation maximale possible : -90% via Savings Plans + right-sizing (557€ → 57€/mois)