Dépannage du Réseau Docker : Résoudre les Problèmes de Connectivité Efficacement
Résolvez les problèmes réseau Docker avec le DNS des conteneurs, les réseaux définis par l'utilisateur, la publication de ports, l'accès à l'hôte, le DNS et les pare-feux.
Dépannage du Réseau Docker : Résoudre les Problèmes de Connectivité Efficacement
Les problèmes réseau Docker sont beaucoup plus faciles à résoudre lorsque vous nommez la direction de la connexion défaillante. "Le conteneur ne peut pas se connecter" est trop vague. L'hôte essaie-t-il d'atteindre un conteneur ? Un conteneur essaie-t-il d'en atteindre un autre ? Un conteneur essaie-t-il d'atteindre Internet ? Le trafic entre-t-il depuis une autre machine ? Chaque chemin utilise un comportement Docker différent.
Commencez par écrire le chemin en langage clair :
navigateur sur l'hôte -> localhost:8080 -> port du conteneur 80
conteneur api -> conteneur db -> port 5432
conteneur worker -> internet public -> api.example.com:443
ordinateur portable distant -> IP publique du serveur -> port de conteneur publié
Une fois que vous connaissez le chemin, vous pouvez tester chaque saut au lieu de modifier les réseaux au hasard.
Connaître les modes réseau Docker de base
La plupart des configurations Docker sur un seul hôte utilisent le réseau bridge. Docker crée un réseau virtuel sur l'hôte, attribue des adresses IP privées aux conteneurs et peut publier des ports de conteneur sélectionnés sur l'hôte.
Le réseau bridge par défaut fonctionne, mais les réseaux bridge définis par l'utilisateur sont meilleurs pour les applications car ils fournissent un DNS intégré par nom de conteneur. Cela signifie qu'un conteneur api peut atteindre un conteneur db à db:5432 si les deux sont attachés au même réseau défini par l'utilisateur.
Créez-en un comme ceci :
docker network create appnet
docker run -d --name db --network appnet postgres:16
docker run -d --name api --network appnet my-api
D'autres modes existent. Le réseau host partage l'espace de noms réseau de l'hôte et supprime le comportement normal de publication de ports ; il est utile dans certains cas Linux mais réduit l'isolation. none donne au conteneur aucun réseau. overlay est pour le réseau multi-hôte Docker Swarm. Compose crée automatiquement des réseaux définis par l'utilisateur pour les projets, sauf si vous configurez autrement.
"Réseau non trouvé"
Cette erreur signifie généralement que le nom du réseau est incorrect ou que le réseau existe dans un contexte différent de celui attendu par la commande.
Vérifiez les réseaux disponibles :
docker network ls
Inspectez celui que vous avez l'intention d'utiliser :
docker network inspect appnet
S'il n'existe pas, créez-le :
docker network create appnet
Avec Compose, le nom réel du réseau peut être préfixé par le nom du projet. Un réseau appelé backend dans compose.yml peut apparaître comme myproject_backend. Utilisez :
docker compose ps
docker network ls
Si vous avez déclaré un réseau Compose externe, Compose ne le créera pas pour vous :
networks:
appnet:
external: true
Dans ce cas, créez-le manuellement ou supprimez external: true si Compose doit le gérer.
La communication conteneur à conteneur échoue
Pour que deux conteneurs communiquent par nom, ils doivent généralement être sur le même réseau défini par l'utilisateur. Confirmez d'abord cela :
docker network inspect appnet
Recherchez les deux conteneurs dans la section Containers.
Ensuite, testez à partir d'un conteneur disposant d'outils de base. Votre image d'application peut ne pas inclure curl, dig ou ping, et ce n'est pas grave. Utilisez un conteneur de débogage temporaire sur le même réseau :
docker run --rm -it --network appnet nicolaka/netshoot
Depuis l'intérieur :
dig db
curl -v http://api:8080/health
nc -vz db 5432
Si le DNS échoue, les conteneurs ne sont probablement pas sur le même réseau défini par l'utilisateur ou vous utilisez le réseau bridge par défaut en attendant une résolution de nom qu'il ne fournit pas de la même manière. Si le DNS fonctionne mais que la connexion échoue, vérifiez si le service de destination écoute sur le port attendu.
À l'intérieur du conteneur de destination :
docker exec -it api sh
ss -ltnp || netstat -ltnp
Une erreur courante consiste à lier l'application à 127.0.0.1 à l'intérieur du conteneur. Cela écoute uniquement sur le loopback à l'intérieur de ce conteneur. Les autres conteneurs ne peuvent pas l'atteindre. Configurez l'application pour écouter sur 0.0.0.0.
Assurez-vous également d'utiliser le port du conteneur, et non le port publié sur l'hôte, pour le trafic conteneur à conteneur. Si la base de données écoute sur le port 5432 dans le conteneur, les autres conteneurs doivent utiliser db:5432, et non localhost:15432 ou le port hôte publié.
L'hôte ne peut pas atteindre un conteneur
Pour que l'hôte atteigne un service dans un conteneur en réseau bridge, vous avez normalement besoin d'un port publié :
docker run -d --name web -p 8080:80 nginx
Cela mappe le port hôte 8080 au port conteneur 80. Testez depuis l'hôte :
curl -v http://localhost:8080
Vérifiez ce que Docker a publié :
docker port web
docker ps --format 'table {{.Names}} {{.Ports}}'
S'il n'y a pas de mappage de port, EXPOSE dans le Dockerfile ne publie pas le port. EXPOSE est une documentation et des métadonnées. Vous avez toujours besoin de -p ou des ports: de Compose.
Si le port est publié mais que la connexion échoue, vérifiez quatre choses :
- L'application écoute à l'intérieur du conteneur sur le port du conteneur.
- L'application écoute sur
0.0.0.0, pas seulement sur127.0.0.1. - Aucun pare-feu hôte ne bloque le port hôte.
- Aucun autre processus ne possède déjà le port hôte.
Trouvez les conflits de ports hôtes :
sudo lsof -i :8080
# ou
sudo ss -ltnp 'sport = :8080'
Pour Compose, rappelez-vous la syntaxe :
ports:
- "8080:80"
Le côté gauche est le port hôte. Le côté droit est le port du conteneur.
Le conteneur ne peut pas atteindre Internet
Testez la connectivité IP et le DNS séparément :
docker exec -it app sh
ping -c 2 1.1.1.1
ping -c 2 example.com
Certaines images n'incluent pas ping. Utilisez curl si disponible :
curl -I https://example.com
Si l'IP fonctionne mais que les noms échouent, c'est un problème DNS. Vérifiez :
cat /etc/resolv.conf
Docker injecte normalement les paramètres du résolveur. Les VPN d'entreprise, le DNS personnalisé et le réseau Docker Desktop peuvent compliquer cela. Vous pouvez configurer le DNS au niveau du démon dans les paramètres du démon Docker, ou passer le DNS pour un conteneur spécifique :
docker run --dns 1.1.1.1 ...
N'utilisez pas aveuglément un DNS public dans des environnements d'entreprise où les noms internes doivent être résolus. Utilisez les serveurs DNS appropriés pour le réseau.
Si ni l'IP ni le DNS ne fonctionnent, vérifiez si le conteneur est sur --network none, si les règles du pare-feu hôte/NAT sont cassées, si le démon Docker a des paramètres réseau personnalisés et si l'hôte lui-même a accès à Internet.
Un conteneur doit atteindre un service sur l'hôte
Depuis un conteneur, localhost signifie le conteneur lui-même, pas l'hôte. C'est l'une des surprises réseau Docker les plus courantes.
Sur Docker Desktop, host.docker.internal se résout généralement en l'hôte. Sur le moteur Docker moderne pour Linux, vous pouvez ajouter une entrée de passerelle hôte :
docker run --add-host=host.docker.internal:host-gateway ...
Ensuite, le conteneur peut appeler :
curl http://host.docker.internal:3000
Assurez-vous que le service hôte écoute sur une adresse accessible depuis Docker, et non seulement sur une liaison loopback que Docker ne peut pas atteindre dans votre environnement. Si un serveur de développement local ne se lie qu'à 127.0.0.1, vous devrez peut-être le lier à 0.0.0.0 ou à l'interface hôte, selon le système d'exploitation et les exigences de sécurité.
Les machines distantes ne peuvent pas atteindre le conteneur
Si l'hôte peut atteindre localhost:8080 mais qu'une autre machine ne peut pas atteindre server-ip:8080, Docker peut être en bon état. Vérifiez le pare-feu hôte, le groupe de sécurité cloud, le routeur/NAT et si Docker a publié uniquement sur le loopback.
Ceci publie sur toutes les interfaces hôtes :
docker run -p 8080:80 nginx
Ceci publie uniquement sur localhost :
docker run -p 127.0.0.1:8080:80 nginx
La publication uniquement sur loopback est souvent souhaitable pour le développement local ou les configurations de proxy inverse, mais elle bloquera l'accès à distance par conception.
Sur les serveurs cloud, vérifiez également les pare-feux du fournisseur. Ouvrir ufw sur la VM n'aide pas si le groupe de sécurité cloud bloque toujours le port.
Erreurs réseau Compose
Compose donne à chaque service un nom DNS basé sur le nom du service. Si votre service s'appelle db, les autres services doivent généralement se connecter à db, pas à localhost.
Exemple :
services:
api:
build: .
environment:
DATABASE_URL: postgres://postgres:postgres@db:5432/app
depends_on:
- db
db:
image: postgres:16
depends_on contrôle l'ordre de démarrage, pas l'état de préparation. Le conteneur de base de données peut démarrer avant que Postgres ne soit prêt à accepter les connexions. Votre application doit réessayer les connexions ou utiliser un modèle de démarrage tenant compte des vérifications de santé.
Distinguer également ports de expose. ports publie sur l'hôte. expose documente ou expose les ports aux services liés mais ne les rend pas accessibles depuis l'hôte de la même manière.
Débogage au niveau des paquets
Lorsque les vérifications normales n'expliquent pas le problème, utilisez une image de débogage réseau :
docker run --rm -it --network container:<conteneur-cible> nicolaka/netshoot
Cela rejoint l'espace de noms réseau du conteneur cible, ce qui vous permet d'inspecter le réseau du même point de vue sans installer d'outils dans l'image de l'application.
Les commandes utiles incluent :
ip addr
ip route
cat /etc/resolv.conf
dig nom-service
curl -v http://nom-service:port
tcpdump -nn -i any port 8080
Utilisez tcpdump lorsque vous devez savoir si les paquets arrivent. Si les paquets n'arrivent jamais, regardez avant le conteneur : publication, pare-feu, routage, équilibreur de charge. Si les paquets arrivent et qu'aucune réponse ne part, regardez à l'intérieur du conteneur ou de l'application.
Un flux de dépannage court
Utilisez cet ordre pour la plupart des problèmes réseau Docker :
- Définissez le chemin exact : hôte vers conteneur, conteneur vers conteneur, conteneur vers Internet, ou distant vers hôte vers conteneur.
- Vérifiez l'attachement au réseau avec
docker network inspect. - Vérifiez la résolution de nom depuis le côté source.
- Vérifiez si le processus de destination écoute sur la bonne interface et le bon port.
- Vérifiez la publication de port uniquement pour le trafic qui traverse de l'hôte au conteneur.
- Vérifiez le pare-feu, le VPN, le proxy, le DNS et les règles de sécurité cloud en dehors de Docker.
La plupart des problèmes réseau Docker ne sont pas des bugs profonds de Docker. Ce sont généralement des noms incorrects, des ports incorrects, une liaison loopback, des ports publiés manquants, des hypothèses DNS ou un trafic testé du mauvais côté de la frontière.