Load Balancing in Docker
Docker provides multiple layers of load balancing, from simple DNS round-robin to IPVS-based virtual IPs.
DNS Round-Robin
The simplest form. When multiple containers share a network alias, Docker's embedded DNS returns all their IPs in rotation.
docker network create lb-demo
for i in 1 2 3; do
docker run -d --name app$i --network lb-demo --network-alias app nginx
done
# Each nslookup rotates through the three IPs
docker run --rm --network lb-demo alpine nslookup app
Limitation: DNS TTL caching in clients can mean traffic isn't balanced evenly. Use VIP-based LB for production.
Docker Swarm VIP Load Balancing
Swarm assigns a Virtual IP (VIP) to each service. IPVS on the swarm nodes distributes connections to healthy replicas.
Client → VIP (10.0.0.5)
│
IPVS (kernel)
├── Replica 1 (10.0.0.6)
├── Replica 2 (10.0.0.7)
└── Replica 3 (10.0.0.8)
The VIP is stable — it doesn't change when replicas are rescheduled.
Swarm Ingress (External Load Balancing)
The ingress routing mesh handles external traffic:
docker service create \
--name web \
--publish published=80,target=80 \
--replicas 3 \
nginx
All nodes listen on port 80. IPVS distributes to replicas cluster-wide.
Internet → node1:80 (no replica here)
→ iptables REDIRECT
→ ingress network
→ IPVS → replica on node2 or node3
Layer 7 Load Balancing with Traefik
For HTTP routing, Traefik is a popular reverse proxy in the Docker ecosystem:
# docker-compose.yml with Traefik
services:
traefik:
image: traefik:v3
command:
- "--providers.docker=true"
- "--entrypoints.web.address=:80"
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
web:
image: nginx
labels:
- "traefik.http.routers.web.rule=Host(`app.example.com`)"
- "traefik.http.services.web.loadbalancer.server.port=80"
deploy:
replicas: 3
Traefik reads Docker labels and automatically configures routing and load balancing. Supports sticky sessions, health checks, and weighted balancing.
NGINX as a Load Balancer
upstream backend {
server app1:8080 weight=3;
server app2:8080 weight=1;
server app3:8080 backup;
least_conn; # least-connections algorithm
keepalive 32;
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
Health Checks & LB
Docker health checks integrate with Swarm routing:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s
Unhealthy replicas are removed from the IPVS table automatically.
Summary
- DNS round-robin: simple but cache-limited
- Swarm VIP: stable virtual IP backed by IPVS, production-ready
- Routing mesh: any node receives external traffic, IPVS distributes
- Traefik: L7 proxy with auto-discovery via Docker labels
- Health checks ensure only healthy containers receive traffic