DCNA
Docker Certified Network Associate
DCNALoad Balancing

Load Balancing dans Docker

Le load balancing distribue les requêtes entrantes entre plusieurs containers pour éviter qu'un seul soit surchargé. Docker propose plusieurs mécanismes, du plus simple (DNS round-robin) au plus robuste (IPVS en mode kernel).

Les 3 niveaux de load balancing Docker

MécanismeNiveauCas d'usageStabilité
DNS round-robinApplicationDev, testsFaible (cache DNS)
VIP + IPVS (Swarm)Kernel L4Production SwarmÉlevée
Reverse proxy L7 (Traefik/Nginx)Application L7HTTP/HTTPS avec routingÉlevée + features

DNS Round-Robin : la base

Quand plusieurs containers partagent le même network alias, Docker retourne toutes leurs IPs en rotation à chaque requête DNS.

docker network create lb-demo

# Lancer 3 instances avec le même alias
for i in 1 2 3; do
  docker run -d --name app$i --network lb-demo --network-alias app nginx
done

# Chaque nslookup retourne les IPs dans un ordre différent
docker run --rm --network lb-demo alpine nslookup app
# Address 1: 172.28.0.2  app1
# Address 2: 172.28.0.3  app2
# Address 3: 172.28.0.4  app3

Limitation majeure : les clients HTTP et JVM mettent en cache les réponses DNS. Résultat : toutes les requêtes d'un client peuvent aller sur le même container pendant un moment, annulant l'effet de distribution.

Utiliser en développement ou pour des clients qui ne cachent pas le DNS. En production → VIP ou reverse proxy.

VIP + IPVS (Swarm) : production-ready

Swarm attribue un Virtual IP (VIP) stable à chaque service. IPVS (IP Virtual Server) est un module du noyau Linux qui distribue les connexions TCP/UDP de manière ultra-performante.

Container client → DNS "api" → VIP 10.0.9.5
                                    │
                               IPVS (kernel)
                               ├── Replica 1 (10.0.9.6) — host-a
                               ├── Replica 2 (10.0.9.7) — host-b
                               └── Replica 3 (10.0.9.8) — host-a

Algorithme : Round-robin par défaut. IPVS choisit au niveau de la connexion (pas de la requête), donc une connexion TCP longue restera sur le même replica.

# Créer un service Swarm avec 3 replicas
docker service create \
  --name api \
  --replicas 3 \
  --network my-overlay \
  --endpoint-mode vip \
  myapi:latest

# Le VIP ne change jamais, même si les replicas redémarrent
docker service inspect api --format '{{json .Endpoint.VirtualIPs}}'
# [{"NetworkID":"...", "Addr":"10.0.9.5/24"}]

Load Balancing Externe : le Routing Mesh

Pour le trafic externe, le routing mesh de Swarm permet à n'importe quel node du cluster de recevoir et router le trafic, même sans replica local.

docker service create \
  --name web \
  --publish published=80,target=80 \
  --replicas 3 \
  nginx

# node-a, node-b, node-c écoutent tous sur :80
# Même si un node n'a pas de replica, il route vers un node qui en a un
Client → http://node-c:80
              │
    node-c : pas de replica web ici
              │
         iptables REDIRECT → ingress network
              │
         IPVS → replica sur node-a ou node-b

Load Balancing L7 avec Traefik

Pour du routing HTTP (par domaine, par chemin, TLS), utiliser un reverse proxy comme Traefik. Traefik s'intègre avec Docker via les labels et se reconfigure automatiquement quand des containers démarrent ou s'arrêtent.

services:
  traefik:
    image: traefik:v3
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
      - "--entrypoints.websecure.address=:443"
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro

  api:
    image: myapi
    deploy:
      replicas: 3
    labels:
      - "traefik.http.routers.api.rule=Host(`api.example.com`)"
      - "traefik.http.services.api.loadbalancer.server.port=8080"
      # Sticky sessions (même client → même replica)
      - "traefik.http.services.api.loadbalancer.sticky.cookie=true"

  web:
    image: nginx
    labels:
      - "traefik.http.routers.web.rule=Host(`app.example.com`)"
      - "traefik.http.services.web.loadbalancer.server.port=80"

Traefik détecte les containers, lit leurs labels, et configure le routing dynamiquement.

Load Balancing avec NGINX

Pour plus de contrôle sur les algorithmes :

upstream backend {
    server app1:8080 weight=3;   # app1 reçoit 3x plus de trafic
    server app2:8080 weight=1;
    server app3:8080 backup;     # backup : utilisé seulement si app1/app2 sont down

    least_conn;                  # algorithme : connexion la moins chargée
    keepalive 32;                # connexions persistantes
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_next_upstream error timeout;  # retry sur le prochain server si erreur
    }
}

Algorithmes disponibles dans Nginx :

  • (par défaut) round-robin
  • least_conn : vers le server avec le moins de connexions actives
  • ip_hash : même client → même server (sessions)
  • random : serveur aléatoire

Health Checks et LB

Docker arrête automatiquement d'envoyer du trafic vers un container marqué comme unhealthy.

# Dans docker-compose.yml ou Dockerfile
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost/health"]
  interval: 10s       # fréquence du check
  timeout: 5s         # délai max pour la réponse
  retries: 3          # nombre d'échecs avant "unhealthy"
  start_period: 30s   # délai avant de commencer les checks (démarrage app)
# Voir l'état de santé
docker ps  # STATUS: "Up 5 minutes (healthy)" ou "(unhealthy)"
docker inspect my-container | grep -A 5 Health

Dans Swarm, un replica unhealthy est automatiquement retiré du VIP IPVS et un nouveau est planifié.

Résumé

  • DNS round-robin : simple, mais le caching DNS réduit l'efficacité — pour dev seulement
  • VIP + IPVS (Swarm) : distribue au niveau kernel, VIP stable, production-ready
  • Routing mesh : tout node reçoit le trafic externe, même sans replica local
  • Traefik : reverse proxy L7 avec auto-découverte Docker et routing HTTP/TLS
  • Health checks : les containers unhealthy sont automatiquement exclus du load balancing