Les fondamentaux du cloud computing
Conteneurs et microservices
Ce qu'un conteneur empaquette réellement, pourquoi diviser un monolithe en microservices change la façon dont une équipe livre et met à l'échelle, et ce qu'un orchestrateur comme Kubernetes ajoute une fois que vous avez plus de conteneurs que vous ne pouvez en gérer à la main.
- Expliquer ce qu'est un conteneur et pourquoi il démarre plus vite qu'une machine virtuelle
- Décrire comment une image de conteneur garde l'environnement d'exécution identique, du poste d'un développeur jusqu'à la production
- Distinguer une application monolithique d'une architecture en microservices par la façon dont chacune est déployée et mise à l'échelle
- Identifier ce qu'ajoute l'orchestration de conteneurs par rapport à la gestion manuelle de conteneurs individuels
- Reconnaître les compromis opérationnels qu'introduisent les microservices en échange d'une mise à l'échelle et d'un déploiement indépendants
La dernière leçon répondait à qui exécute le code. Celle-ci demande comment il est construit
La dernière leçon a laissé le calcul répondu : une fonction serverless, une machine virtuelle, ou quelque chose entre les 2, exécute votre code, et le fournisseur prend en charge plus ou moins du travail environnant selon votre choix. Rien de tout cela ne dit comment l'application elle-même est assemblée. Une application qui a démarré comme un seul grand code, un seul déploiement, une seule équipe, rencontre un problème précis en grandissant : un petit correctif sur le parcours de paiement oblige à tester et redéployer toute l'application, catalogue, comptes et le reste, et une pointe de trafic sur une seule partie de l'application vous force à mettre à l'échelle le tout. Conteneurs et microservices sont 2 idées distinctes qui, ensemble, résolvent exactement ce problème.
Ce qu'un conteneur empaquette réellement
Un conteneur est un processus isolé, empaqueté avec tout ce dont il a besoin pour s'exécuter : votre code, son runtime, et ses dépendances, le tout dans une seule unité autonome. Empaquetez une application Node.js dans une image de conteneur, et cette image s'exécute à l'identique qu'elle démarre sur le poste d'un développeur, un serveur de test, ou un cluster de production, parce que l'image transporte son propre runtime au lieu de dépendre de ce qui se trouve déjà installé sur l'hôte.
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm install --production
COPY . .
CMD ["node", "server.js"]
docker build -t service-paiement:1.0 .
docker run -p 3000:3000 service-paiement:1.0
Ce Dockerfile décrit l'image ; docker build l'empaquette ; docker run démarre un conteneur à partir d'elle. La leçon sur le calcul avait déjà placé les conteneurs sur le spectre contrôle-confort, démarrant en secondes là où une machine virtuelle prend des minutes, parce qu'un conteneur partage le noyau du système d'exploitation hôte au lieu de démarrer son propre OS invité complet.
Du monolithe aux microservices
Un monolithe, c'est un seul code, un seul déploiement, et généralement une seule base de données partagée, peu importe le nombre de fonctionnalités distinctes qu'il contient. Une architecture en microservices découpe cette même application en une suite de petits services déployables indépendamment, chacun construit autour d'une capacité métier (catalogue, panier, paiement, comptes utilisateurs) et communiquant par des API légères plutôt que par des appels de fonction en mémoire. Chaque service possède en général sa propre base de données au lieu d'en partager une, ce qui le rend déployable et évolutif de façon autonome.
Reprenez le scénario de la pointe de trafic. Dans un monolithe, un triplement du trafic de paiement force à mettre à l'échelle tout le déploiement, catalogue et comptes inclus, puisqu'il n'existe qu'une seule unité déployable à faire évoluer. Découpé en microservices, le service de paiement se met à l'échelle seul, et catalogue et comptes restent exactement comme avant, parce que chacun est désormais une pièce séparée, déployable indépendamment.
Le compromis : l'indépendance contre la coordination
Rien de tout cela n'est gratuit. Découper un monolithe en microservices échange la simplicité d'un seul code contre un ensemble de problèmes nouveaux qui n'apparaissent qu'une fois les services séparés. Un appel du service de paiement vers le service utilisateur traverse maintenant un réseau au lieu d'appeler une fonction dans le même processus, ce qui signifie qu'il peut expirer ou échouer de façons qu'un appel en mémoire ne connaît jamais. Des données décentralisées, chaque service avec sa propre base, signifient renoncer à une transaction unique sur toute la requête au profit d'une cohérence à terme entre services. Et une requête client unique qui traverse 5 services est plus difficile à déboguer qu'une requête qui n'en touche qu'un, puisqu'il n'existe plus une seule pile d'appels à lire. Plus de services n'est pas automatiquement mieux, c'est un échange délibéré de simplicité contre indépendance, qui ne rapporte qu'une fois qu'une équipe dispose de l'outillage opérationnel pour le gérer, exactement ce que couvre la section suivante.
Orchestration : gérer plus de conteneurs qu'un humain ne peut suivre
Faites tourner 1 seul conteneur à la main, et docker run suffit. Faites tourner 3 répliques d'un service de paiement pour la redondance, plus un service catalogue, plus un service panier, chacun avec ses propres répliques, et surveiller tout cela manuellement cesse rapidement de fonctionner. Un orchestrateur de conteneurs comme Kubernetes prend une description déclarative de ce que vous voulez et travaille en continu pour faire correspondre la réalité à cette description.
apiVersion: apps/v1
kind: Deployment
metadata:
name: service-paiement
spec:
replicas: 3
selector:
matchLabels:
app: service-paiement
template:
metadata:
labels:
app: service-paiement
spec:
containers:
- name: paiement
image: service-paiement:2.1
ports:
- containerPort: 8080
Cette ligne replicas: 3 est une déclaration, pas une commande ponctuelle. Si l'une des 3 répliques tombe, Kubernetes remarque l'écart entre l'état déclaré et la réalité et démarre automatiquement un remplacement, une capacité appelée auto-guérison. Kubernetes gère aussi la découverte de service et la répartition de charge entre ces répliques, et déploie les mises à jour progressivement plutôt que d'un coup, si bien qu'une équipe arrête de surveiller les conteneurs à la main et commence à décrire l'état qu'elle veut.
Repères d'examen : reconnaître le bon choix dans un scénario
| L'énoncé dit... | Pointe vers |
|---|---|
| "Empaqueter une fois, exécuter à l'identique partout" | Conteneur |
| "Des équipes indépendantes livrent indépendamment, chacune possède ses données" | Microservices |
| "Redémarrer automatiquement les instances en échec, déployer les mises à jour progressivement" | Orchestration de conteneurs (Kubernetes) |
| "Un seul code, un seul déploiement, une seule base de données" | Monolithe |
Ce qu'il faut retenir
Découper une application en microservices et empaqueter chaque pièce en conteneur sont 2 décisions distinctes qui se renforcent l'une l'autre : la déployabilité indépendante promise par les microservices ne tient que si chaque pièce peut réellement être livrée et mise à l'échelle seule, et un conteneur est exactement ce qui rend cela possible en pratique. Rien de tout cela, les builds, les déploiements, le nombre toujours croissant de pièces mobiles, ne reste gérable à la main bien longtemps. La prochaine leçon couvre les pratiques et l'outillage, DevOps et infrastructure as code, qui gardent tout cela gérable.
