Container DNS & Service Discovery
Dans un cluster Docker, les IPs des containers changent à chaque redémarrage. Dur coder 172.17.0.4 dans ta config = cassé dès le prochain docker restart. La solution : le DNS embarqué Docker, qui permet de contacter un container par son nom plutôt que par son IP.
Comment fonctionne le DNS embarqué
Sur les user-defined networks, Docker injecte automatiquement un serveur DNS local dans chaque container à l'adresse 127.0.0.11:53.
# Créer un réseau et voir la config DNS
docker network create demo
docker run --rm --network demo alpine cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0
# Sur le bridge par défaut, pas de DNS Docker
docker run --rm alpine cat /etc/resolv.conf
# nameserver 8.8.8.8 ← DNS de l'hôte, pas de Docker
Ce qui se passe concrètement
Quand le container A fait ping db :
Container A
│
▼ DNS query: "db" → 127.0.0.11:53
│
▼ Docker DNS Server (dans le daemon Docker)
│ ├── "db" est un container sur ce réseau → OUI → renvoie 172.28.0.3
│ └── inconnu → transfère au DNS upstream (DNS de l'hôte)
│
▼ Container A reçoit: db = 172.28.0.3
│
▼ Connection TCP vers 172.28.0.3
Le serveur DNS Docker intercepte les requêtes via iptables et les redirige vers le daemon Docker (qui connaît tous les containers du réseau). C'est pour ça que ça ne fonctionne que sur les user-defined networks — le DNS embarqué ne tourne que là.
Résolution par nom de container
docker network create demo
docker run -d --name web --network demo nginx
docker run -d --name db --network demo postgres
# Depuis "web", résoudre "db" par son nom
docker exec web ping db
# PING db (172.28.0.3): 56 data bytes ...
docker exec web nslookup db
# Server: 127.0.0.11
# Address 1: 127.0.0.11
# Name: db
# Address 1: 172.28.0.3
Si db redémarre et change d'IP, le DNS Docker se met à jour automatiquement — c'est ça la vraie valeur.
Network Aliases : plusieurs noms pour un container
docker run -d \
--name primary-db \
--network demo \
--network-alias database \
--network-alias db \
postgres
# Les deux noms pointent sur le même container
docker run --rm --network demo alpine nslookup database
# Address: 172.28.0.3
docker run --rm --network demo alpine nslookup db
# Address: 172.28.0.3
Alias partagés pour la haute disponibilité
Si plusieurs containers ont le même alias, Docker retourne toutes leurs IPs en round-robin (load balancing DNS basique) :
docker run -d --name replica1 --network demo --network-alias db-read postgres
docker run -d --name replica2 --network demo --network-alias db-read postgres
docker run --rm --network demo alpine nslookup db-read
# Name: db-read
# Address 1: 172.28.0.4 (replica1)
# Address 2: 172.28.0.5 (replica2)
À chaque nouvelle requête DNS, les IPs sont retournées dans un ordre différent — charge répartie entre les replicas.
Service Discovery dans Docker Compose
Compose crée automatiquement un réseau pour le projet, et chaque nom de service devient un nom DNS :
# docker-compose.yml
services:
web:
image: nginx
# peut accéder à "api" et "redis" directement par nom
api:
image: myapi
environment:
DATABASE_URL: postgres://db:5432/mydb # "db" = nom du service
CACHE_URL: redis://redis:6379 # "redis" = nom du service
db:
image: postgres
redis:
image: redis
docker compose up -d
# Crée automatiquement: myproject_default (réseau bridge)
# "db", "api", "redis", "web" sont tous résolvables par DNS
docker compose exec api ping db # fonctionne
Multi-réseau : un container, plusieurs DNS
Un container peut être connecté à plusieurs réseaux. Il aura une IP dans chacun, et son nom sera résolvable depuis chacun :
docker network create frontend-net
docker network create backend-net
# Le container "api" est connecté aux deux réseaux
docker run -d --name api --network frontend-net myapi
docker network connect backend-net api
# "api" est résolvable depuis frontend-net ET depuis backend-net
docker exec web ping api # web est sur frontend-net → OK
docker exec db ping api # db est sur backend-net → OK
C'est le pattern classique pour un container "pont" entre deux tiers.
Configuration DNS personnalisée
# DNS personnalisé pour un container
docker run --dns 1.1.1.1 --dns 8.8.8.8 --dns-search mycompany.local nginx
# DNS global pour tous les containers (dans /etc/docker/daemon.json)
{
"dns": ["1.1.1.1", "8.8.8.8"],
"dns-search": ["mycompany.local", "internal.corp"]
}
# Après modification de daemon.json
sudo systemctl reload docker
Flux de résolution DNS complet
Container query: "external-api.example.com"
│
▼ 127.0.0.11:53
│
▼ Docker DNS : inconnu dans ce réseau
│
▼ Upstream DNS (DNS de l'hôte ou --dns configuré)
│
▼ Réponse : 93.184.216.34
Container query: "my-db" (container sur le même réseau)
│
▼ 127.0.0.11:53
│
▼ Docker DNS : "my-db" connu → 172.28.0.3
│
▼ Réponse immédiate, pas besoin d'aller sur internet
Diagnostiquer les problèmes DNS
# 1. Vérifier que le container est sur un user-defined network
docker inspect my-container --format '{{json .NetworkSettings.Networks}}'
# Doit avoir un réseau autre que "bridge" (default)
# 2. Tester directement le DNS Docker
docker exec my-container nslookup other-service 127.0.0.11
# 3. Vérifier le resolv.conf dans le container
docker exec my-container cat /etc/resolv.conf
# 4. Si sur le bridge par défaut → migrer sur un user-defined network
docker network create app-net
docker run --network app-net ...
Résumé
- Le DNS Docker (
127.0.0.11) ne fonctionne que sur les user-defined networks - Les containers se découvrent par leur nom de container ou network alias
- Les alias partagés permettent un round-robin DNS entre plusieurs containers
- Docker Compose enregistre automatiquement chaque nom de service comme DNS
- Les containers multi-réseau ont une IP et un nom DNS dans chaque réseau