Ce sont trois niveaux d'abstraction. Plus tu montes, moins tu gères de serveur — mais moins tu contrôles, et le modèle de coût change du tout au tout.
Je me pose trois questions, dans cet ordre.
Événementiel, en pics rares, ou proche de zéro la plupart du temps → Lambda. Tu ne paies rien quand ça dort.
Une API qui tourne 24/7, déjà en Docker, plusieurs services → ECS/Fargate. Le juste milieu.
PHP historique, GPU, config système précise, ou tu veux le coût le plus bas à charge stable → EC2.
Moins tu es nombreux, plus tu montes en abstraction : laisse AWS gérer les machines pour toi.
Pour EC2, le déploiement est celui de mes guides Langfuse et e-commerce : machine, reverse proxy, HTTPS, pm2 ou Docker.
Il n'y a pas de gagnant absolu : le bon choix dépend de ta courbe de trafic. En cas de doute sur une charge stable, ECS/Fargate est rarement un mauvais pari.
L'arbre plus haut dit « trafic intermittent → Lambda », mais avant de tout y mettre il faut connaître trois murs que je heurte régulièrement en production. Ce sont eux qui décident si Lambda tient la charge ou pas.
Une invocation ne peut pas dépasser 900 secondes, c'est un plafond dur non négociable, avec au maximum 10 240 MB de RAM ([quotas Lambda](https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html)). Un batch qui dépasse → tu découpes, tu passes en Step Functions, ou tu bascules la tâche sur Fargate.
Par défaut, 1 000 exécutions simultanées pour tout ton compte dans une région, partagées entre toutes tes fonctions ([function scaling](https://docs.aws.amazon.com/lambda/latest/dg/lambda-concurrency.html)). Au-delà, throttling : les requêtes tombent. C'est augmentable, mais il faut le demander — et penser à la reserved concurrency pour protéger tes fonctions critiques.
Quand aucun environnement chaud n'est dispo, Lambda en initialise un neuf : c'est le cold start, quelques centaines de ms à plusieurs secondes selon le runtime et tes dépendances. Gênant sur une API user-facing, invisible sur du batch.
Java, Python 3.12+, .NET 8+
tous les runtimes
Ma règle : SnapStart d'abord quand le runtime le supporte (c'est gratuit), provisioned concurrency seulement si j'ai un SLA de latence strict que SnapStart ne tient pas. Et si les fonctions tournent longtemps ou en continu, je relis l'arbre — souvent c'est le signe qu'il faut passer sur ECS.
Une fois que tu as choisi les conteneurs, reste le sous-choix : Fargate (AWS gère les machines) ou launch type EC2 (tu gères ta flotte sous ECS). Ce n'est pas religieux, c'est une histoire de taux d'utilisation.
Le blog AWS Fargate vs EC2 chiffre le croisement : à faible taux de réservation, Fargate peut être jusqu'à ~87 % moins cher qu'une instance sous-utilisée ; à pleine charge, l'EC2 launch type repasse devant avec plus de 20 % d'économie. Le point de bascule, c'est ta capacité à remplir tes instances.
Beaucoup d'équipes finissent en mixte : Fargate pour les services en pics ou peu utilisés, EC2 pour le cœur stable qui justifie un Savings Plan. Tu n'es jamais obligé de choisir un seul launch type pour tout le cluster.
De « ça marche chez moi » à reproductible et observable : IaC, CI/CD, health checks, rollback.
Load balancer, auto-scaling, read replicas, cache — dimensionnés juste pour encaisser un pic.