Skip to content
Learni
View all tutorials
Architecture

Comment architecturer des microservices scalables en 2026

Introduction

Les architectures microservices permettent de découpler les applications monolithiques en services indépendants, chacun responsable d'un domaine métier précis. Cette approche améliore la scalabilité, la résilience et la vitesse de déploiement. En 2026, les équipes utilisent systématiquement des outils comme Kubernetes pour l'orchestration et des brokers de messages pour la communication asynchrone. Ce tutoriel vous guide pas à pas dans la construction d'un système complet composé de deux services Node.js communiquant via RabbitMQ, conteneurisés avec Docker et déployés sur Kubernetes. Chaque étape inclut du code prêt à l'emploi.

Prérequis

  • Node.js 20+
  • Docker Desktop
  • Kubernetes (Minikube ou cluster cloud)
  • Connaissances solides en TypeScript et architecture distribuée
  • RabbitMQ installé localement pour les tests

Service Utilisateurs

user-service/src/index.ts
import express from 'express';
import amqp from 'amqplib';

const app = express();
app.use(express.json());

let channel: any;

async function connectRabbit() {
  const connection = await amqp.connect('amqp://localhost');
  channel = await connection.createChannel();
  await channel.assertQueue('user_created');
}

app.post('/users', async (req, res) => {
  const user = { id: Date.now(), ...req.body };
  await channel.sendToQueue('user_created', Buffer.from(JSON.stringify(user)));
  res.status(201).json(user);
});

connectRabbit().then(() => {
  app.listen(3001, () => console.log('User service on 3001'));
});

Ce service Express expose un endpoint POST et publie un événement sur RabbitMQ après création d'utilisateur. La connexion est établie une seule fois au démarrage pour éviter les fuites de ressources.

Service Commandes

order-service/src/index.ts
import express from 'express';
import amqp from 'amqplib';

const app = express();
app.use(express.json());

let channel: any;

async function connectRabbit() {
  const connection = await amqp.connect('amqp://localhost');
  channel = await connection.createChannel();
  await channel.assertQueue('user_created');
  channel.consume('user_created', (msg) => {
    if (msg) {
      const user = JSON.parse(msg.content.toString());
      console.log('Nouvel utilisateur reçu:', user);
      channel.ack(msg);
    }
  });
}

app.post('/orders', (req, res) => {
  res.status(201).json({ orderId: Date.now(), userId: req.body.userId });
});

connectRabbit().then(() => {
  app.listen(3002, () => console.log('Order service on 3002'));
});

Le service Commandes consomme les événements user_created. L'utilisation de channel.ack garantit que le message n'est supprimé de la file qu'après traitement réussi.

Dockerfile service Utilisateurs

user-service/Dockerfile
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3001
CMD ["node", "dist/index.js"]

Image minimale Alpine pour réduire la surface d'attaque. npm ci assure des builds reproductibles en production.

Docker Compose

docker-compose.yml
version: '3.8'
services:
  rabbitmq:
    image: rabbitmq:3-management
    ports:
      - "5672:5672"
      - "15672:15672"
  user-service:
    build: ./user-service
    ports:
      - "3001:3001"
    depends_on:
      - rabbitmq
  order-service:
    build: ./order-service
    ports:
      - "3002:3002"
    depends_on:
      - rabbitmq

Compose orchestre les trois conteneurs avec dépendances explicites. RabbitMQ expose aussi son interface de gestion pour le débogage.

Déploiement Kubernetes

k8s/user-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
      - name: user-service
        image: user-service:latest
        ports:
        - containerPort: 3001

Trois replicas assurent la haute disponibilité. Le label selector permet à un Service Kubernetes de router le trafic automatiquement.

Bonnes pratiques

  • Utilisez des files de messages pour la communication asynchrone afin de découpler les services
  • Implémentez le pattern Circuit Breaker pour gérer les pannes partielles
  • Versionnez vos APIs et événements
  • Centralisez les logs et métriques avec ELK ou Prometheus
  • Automatisez les tests de contrat entre services

Erreurs courantes à éviter

  • Partager une base de données entre services (crée un couplage fort)
  • Ignorer la gestion des messages dupliqués (idempotence nécessaire)
  • Oublier les health checks Kubernetes
  • Ne pas limiter la taille des payloads dans les files de messages

Pour aller plus loin

Approfondissez l'observabilité et le service mesh avec Istio dans nos formations Learni.