Introduction
La fonctionnalité Context de Docker est un outil puissant qui permet de basculer entre différents points de terminaison Docker, comme un moteur Docker Desktop local, un démon Docker distant via SSH ou un service de conteneurs géré par un fournisseur cloud. Cependant, les problèmes réseau peuvent rapidement transformer cette commodité en confusion. Les conteneurs peuvent ne pas réussir à joindre des services externes, les résolutions DNS peuvent expirer, les ports publiés peuvent refuser les connexions ou le trafic peut être silencieusement bloqué par un pare-feu.
Ce guide propose une approche systématique pour diagnostiquer et corriger les problèmes réseau des contextes Docker, avec des commandes concrètes et les sorties attendues. Que vous soyez un développeur travaillant localement ou un consultant DevOps gérant des contextes distants, les étapes décrites ici vous aideront à isoler le problème et à rétablir rapidement la connectivité.
Inventaire des versions et de l'environnement
Avant de modifier le moindre paramètre, rassemblez des informations sur votre client Docker, vos contextes, votre démon et la topologie du réseau. Cet inventaire évite les erreurs de diagnostic et garantit que vous comprenez l'ampleur du problème.
Vérifiez les versions du client et du serveur Docker
Exécutez docker version pour voir les versions du client et du serveur, ainsi que le système d'exploitation et l'architecture. Pour les contextes distants, la section serveur reflète le démon distant. Exemple de sortie (tronquée) :
Client: Docker Engine - Community
Version: 24.0.5
API version: 1.43
Go version: go1.20.4
Git commit: ced0996
Built: Fri Jul 21 19:36:24 2023
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 24.0.5
API version: 1.43 (minimum version 1.12)
Go version: go1.20.4
Git commit: a61e2b4
Built: Fri Jul 21 19:36:24 2023
OS/Arch: linux/amd64
Experimental: false
Notez que la ligne Context: indique le contexte actuellement actif. Si la version du serveur diffère sensiblement de celle du client, des problèmes de compatibilité peuvent survenir, mais les problèmes réseau sont généralement indépendants des différences mineures de version.
Liste des contextes Docker
docker context ls affiche tous les contextes configurés et leurs points de terminaison. Exemple :
NAME TYPE DESCRIPTION DOCKER ENDPOINT KUBERNETES ENDPOINT ORCHESTRATOR
default * moby Current DOCKER_HOST based config unix:///var/run/docker.sock swarm
remote-ssh ssh Remote Docker host via SSH ssh://user@host
L'astérisque marque le contexte actif. La colonne DOCKER ENDPOINT révèle comment le client se connecte au démon : une socket Unix locale (unix:///var/run/docker.sock) ou un protocole distant (ssh://, tcp://, etc.). Si vous dépannez un contexte distant, assurez-vous que le point de terminaison est joignable avant de vous plonger dans le réseau des conteneurs.
Testez la connectivité de base au démon
Pour un contexte SSH distant, vérifiez la connectivité SSH et la réactivité du démon :
docker --context remote-ssh info
La sortie attendue comprend le système d'exploitation du serveur, la version du noyau, le nombre de conteneurs et d'images, entre autres détails. Si cette commande échoue, le problème est probablement lié à l'authentification SSH ou à l'accès au démon, et non au réseau des conteneurs.
Comprendre la topologie du réseau
Documentez où s'exécutent les conteneurs (moteur local, hôte distant, cloud) et comment vous prévoyez que le trafic circule. Identifiez le pilote réseau Docker utilisé (bridge, overlay, host, macvlan, etc.) avec :
docker network ls
Exemple de sortie :
NETWORK ID NAME DRIVER SCOPE
1a2b3c4d5e6f bridge bridge local
7f8g9h0i1j2k host host local
3l4m5n6o7p8q none null local
Cette étape garantit que les commandes de diagnostic ultérieures sont exécutées sur le bon contexte et le bon réseau.
Chemin de configuration sécurisé
Lorsque des modifications sont nécessaires, rendez-les limitées et réversibles. Évitez de modifier les paramètres globaux du démon Docker sauf en cas d'absolue nécessité ; préférez les ajustements par conteneur ou par réseau.
Utilisez des contextes explicites pour éviter les modifications accidentelles
Préfixez toujours les commandes avec --context <nom> lorsque vous travaillez avec des contextes non par défaut, ou définissez DOCKER_CONTEXT dans votre shell. Par exemple :
export DOCKER_CONTEXT=remote-ssh
Cela garantit que chaque commande Docker dans ce shell cible le démon prévu, évitant les confusions entre local et distant.
Créez un réseau dédié pour des tests isolés
Au lieu de modifier le réseau bridge intégré, créez un réseau bridge personnalisé pour vos conteneurs. Cela vous donne le contrôle sur le sous-réseau et la passerelle, et évite de perturber d'autres conteneurs.
docker network create --driver bridge --subnet 172.28.0.0/16 --gateway 172.28.0.1 testnet
Sortie attendue : l'identifiant du réseau. Utilisez ce réseau pour le dépannage afin que les modifications soient contenues.
Lancez un conteneur de diagnostic avec des paramètres réseau explicites
Démarrez un conteneur attaché à votre réseau de test avec une image connue et remplacez le DNS si nécessaire. Par exemple, pour tester la résolution DNS à l'intérieur du réseau :
docker run -it --rm --network testnet --dns 8.8.8.8 alpine nslookup example.com
Cette commande utilise le DNS public de Google (8.8.8.8), mais vous pouvez le remplacer par votre DNS interne. Si le conteneur ne peut pas résoudre, la sortie affiche un délai d'attente ou une défaillance du serveur, indiquant un problème de chemin réseau.
Publiez les ports explicitement et testez localement
Lors de l'exposition d'un service, liez-le à une interface hôte spécifique pour éviter une exposition involontaire. Utilisez l'option -p avec une adresse IP :
docker run -d --name web --network testnet -p 127.0.0.1:8080:80 nginx
Cela mappe le port 8080 de la boucle locale de l'hôte au port 80 du conteneur. Vérifiez avec curl http://127.0.0.1:8080 - vous devriez voir la page d'accueil de nginx. Si cela échoue, le problème peut venir du service du conteneur ou du mappage de port.
Ajustez les règles du pare-feu uniquement si nécessaire
Si les connexions sont refusées depuis l'extérieur de l'hôte, vérifiez les paramètres du pare-feu. Pour les hôtes Linux utilisant iptables, Docker insère normalement ses propres règles. Cependant, certains outils de pare-feu (comme UFW ou firewalld) peuvent bloquer le trafic Docker. Un test temporaire sûr consiste à autoriser le trafic sur le port publié :
sudo ufw allow 8080/tcp
Testez ensuite la connectivité. N'oubliez pas que désactiver entièrement le pare-feu est risqué ; ajoutez plutôt des règles spécifiques et supprimez-les si nécessaire.
Vérification et diagnostics
Avec la configuration en place, vérifiez la connectivité étape par étape. Commencez depuis l'intérieur du conteneur et progressez vers l'extérieur.
Dans le conteneur : vérifiez les interfaces et les routes
Exécutez ip addr et ip route à l'intérieur d'un conteneur en cours d'exécution (installez iproute2 si nécessaire). Exemple à partir d'un conteneur Alpine :
docker exec -it web ip addr show eth0
La sortie attendue comprend une adresse IP de votre sous-réseau personnalisé (par exemple, 172.28.0.2/16) et l'adresse MAC. Ensuite :
docker exec -it web ip route
Sortie :
default via 172.28.0.1 dev eth0
172.28.0.0/16 dev eth0 proto kernel scope link src 172.28.0.2
Cela confirme que le conteneur a une IP valide et une route par défaut via la passerelle du réseau.
Tests de résolution DNS
Utilisez nslookup ou dig (installez bind-tools dans Alpine) pour tester la résolution de noms depuis l'intérieur du conteneur :
docker exec -it web nslookup example.com
La sortie attendue comprend l'adresse IP résolue et le serveur DNS utilisé. Si le serveur est injoignable, vous pouvez voir :
;; connection timed out; no servers could be reached
Cela indique un problème de configuration DNS ou de chemin réseau.
Vérifiez le fichier /etc/resolv.conf du conteneur pour voir quels serveurs DNS sont configurés :
docker exec -it web cat /etc/resolv.conf
Sortie typique pour un réseau défini par l'utilisateur :
search myproject.local
nameserver 127.0.0.11
options ndots:0
Le 127.0.0.11 est le serveur DNS intégré de Docker, qui transmet les requêtes au DNS configuré de l'hôte. S'il est manquant ou incorrect, le conteneur échouera à résoudre.
Testez la connectivité sortante
Depuis l'intérieur du conteneur, tentez de joindre un service externe par IP et par nom :
docker exec -it web ping -c 4 8.8.8.8
Si ping n'est pas disponible, installez-le ou utilisez wget/curl. Pour un test basé sur le nom :
docker exec -it web wget -O- http://example.com
Si l'IP fonctionne mais que le nom échoue, le problème est le DNS. Si aucun des deux ne fonctionne, vérifiez le routage et le pare-feu.
Testez la connectivité entrante vers les ports publiés
Depuis l'hôte Docker, testez le port publié :
curl http://localhost:8080
Si cela échoue, vérifiez que le conteneur est en cours d'exécution et qu'il écoute :
docker port web
Sortie attendue :
80/tcp -> 127.0.0.1:8080
Cela confirme le mappage de port. Si le mappage est correct mais que la connexion est refusée, vérifiez les journaux du service du conteneur :
docker logs web
Recherchez des erreurs comme "address already in use" ou le service qui n'écoute pas sur le port attendu.
Depuis une machine externe (si vous accédez à l'hôte Docker via le réseau), testez avec l'IP de l'hôte :
curl http://<docker-host-ip>:8080
Si cela échoue alors que localhost réussit, le pare-feu bloque probablement l'accès externe.
Diagnostiquez avec l'inspection du réseau Docker
Inspectez le réseau pour voir les conteneurs connectés et leurs IP :
docker network inspect testnet
La sortie comprend un objet JSON avec une section Containers montrant l'adresse IPv4 de chaque conteneur. Vérifiez que votre conteneur a une adresse et qu'il n'y a pas de conflits.
Utilisez traceroute pour trouver les problèmes de routage
Depuis l'intérieur du conteneur, tracez le chemin vers un hôte externe :
docker exec -it web traceroute 8.8.8.8
Si traceroute n'est pas installé, installez-le ou utilisez mtr. La sortie montre chaque saut ; si elle s'arrête à la passerelle sans autre saut, l'hôte ne transfère peut-être pas les paquets (transfert IP désactivé) ou un pare-feu bloque le trafic sortant.
Modes de défaillance et reprise
Modes de défaillance courants et comment les récupérer.
Défaillance : le conteneur ne peut pas résoudre les noms DNS
Symptômes : nslookup expire ; les applications signalent "unknown host".
Causes :
- Le serveur DNS intégré de Docker n'est pas joignable.
- Le DNS de l'hôte est mal configuré.
- Les paramètres DNS personnalisés sont incorrects.
Étapes de récupération :
- Vérifiez
/etc/resolv.confà l'intérieur du conteneur ; assurez-vous qu'il pointe vers127.0.0.11ou un DNS externe valide. - Vérifiez que la résolution DNS de l'hôte fonctionne (
nslookup example.comsur l'hôte). - Définissez explicitement un DNS fonctionnel dans la commande d'exécution du conteneur (
--dns 8.8.8.8) pour tester. - Si vous utilisez un réseau défini par l'utilisateur, recréez le réseau pour réinitialiser le DNS intégré de Docker.
Défaillance : le port publié n'est pas accessible de l'extérieur
Symptômes : accessible via localhost sur l'hôte, mais pas depuis d'autres machines.
Causes :
- Le pare-feu bloque le port.
- Le conteneur est lié uniquement à la boucle locale (
127.0.0.1au lieu de0.0.0.0). - Problème de routage IP de l'hôte.
Étapes de récupération :
- Vérifiez la liaison de port du conteneur avec
docker port web; si elle affiche127.0.0.1:8080, relancez le conteneur avec-p 0.0.0.0:8080:80. - Ajoutez une règle de pare-feu pour autoriser le port.
- Vérifiez l'adresse IP de l'hôte et que le service écoute sur la bonne interface (
ss -tlnp | grep 8080sur l'hôte).
Défaillance : la communication inter-conteneurs échoue sur un réseau personnalisé
Symptômes : les conteneurs sur le même réseau ne peuvent pas se joindre par nom ou IP.
Causes :
- Conteneurs attachés à des réseaux différents.
- La résolution de noms DNS intégrée ne fonctionne pas.
- Mauvaise configuration du réseau.
Étapes de récupération :
- Utilisez
docker network inspect testnetpour confirmer que les deux conteneurs sont connectés. - Testez d'abord la connectivité par IP ; si l'IP fonctionne mais pas le nom, c'est un problème DNS. Assurez-vous que les conteneurs ont des noms uniques et utilisent le bon alias réseau.
- Si l'IP échoue, vérifiez l'interface bridge sur l'hôte (
ip addr show br-<network-id>). - Recréez le réseau et rattachez les conteneurs si nécessaire.
Retour en arrière : revenir à la configuration d'origine
Si une modification cause des problèmes, revenez en arrière :
- Supprimez les remplacements DNS personnalisés en relançant le conteneur sans
--dns. - Supprimez les règles de pare-feu avec
sudo ufw delete allow 8080/tcp. - Supprimez le réseau personnalisé avec
docker network rm testnet(après avoir arrêté les conteneurs). - Si vous avez modifié les paramètres globaux DNS ou iptables du démon, restaurez les fichiers de configuration précédents et redémarrez Docker.
Vérifications de récupération après le retour en arrière
Après le retour en arrière, répétez les étapes de vérification précédentes pour confirmer que le comportement d'origine est rétabli.
Pièges courants et comment les éviter
Même les utilisateurs Docker expérimentés peuvent tomber dans des pièges réseau. Voici les erreurs les plus fréquentes et comment les éviter.
Utiliser le mauvais contexte par accident
Pourquoi cela arrive : vous avez plusieurs contextes configurés et oubliez lequel est actif. Vous exécutez docker run en pensant déployer sur le serveur distant mais lancez en réalité le conteneur sur votre ordinateur portable.
Comment éviter : vérifiez toujours docker context ls avant les opérations critiques, ou définissez une invite de shell qui affiche le contexte actuel. Pour les scripts, passez explicitement --context <nom>.
Récupération : si vous avez déployé un conteneur sur le mauvais hôte, arrêtez-le et supprimez-le immédiatement avec docker --context <bon-contexte> rm -f <conteneur> pour éviter les fuites de ressources.
Ignorer le DNS intégré de Docker
Pourquoi cela arrive : vous supposez que les conteneurs utilisent directement les serveurs DNS de l'hôte et les configurez comme des IP externes statiques. Lorsque le conteneur est recréé sur un hôte différent, ces IP peuvent être injoignables.
Comment éviter : fiez-vous au DNS intégré de Docker (127.0.0.11) pour la découverte de services sur les réseaux définis par l'utilisateur. Ne remplacez le DNS avec --dns que si vous avez une infrastructure DNS interne spécifique.
Récupération : relancez le conteneur sans les indicateurs DNS personnalisés ; si votre application nécessite un résolveur spécifique, utilisez un fichier de configuration ou une variable d'environnement au lieu de coder en dur.
Lier les services uniquement à la boucle locale
Pourquoi cela arrive : pendant le développement, vous utilisez -p 127.0.0.1:80:80 pour éviter d'exposer le service publiquement. Plus tard, lors du passage en production, vous oubliez de changer la liaison et vous demandez pourquoi les clients externes ne peuvent pas se connecter.
Comment éviter : définissez les liaisons de port dans un fichier compose ou un script avec une variable, et examinez la valeur pour chaque environnement. Documentez clairement quels ports sont destinés uniquement aux tests locaux.
Récupération : relancez le conteneur avec -p 0.0.0.0:80:80 ou l'IP d'interface appropriée, puis testez depuis un autre hôte.
Règles de pare-feu non rechargées ou conflictuelles
Pourquoi cela arrive : vous ajoutez manuellement des règles iptables pendant le dépannage mais ne les persistez pas. Après un redémarrage, les règles disparaissent et la connectivité se rompt à nouveau. Ou bien, un gestionnaire de pare-feu séparé (comme UFW ou firewalld) écrase les règles de Docker.
Comment éviter : utilisez l'outil de pare-feu persistant approprié pour votre distribution (par exemple, netfilter-persistent pour iptables, le service propre d'UFW). Pour la production, fiez-vous à l'infrastructure en tant que code ou à un système de gestion de configuration pour gérer les règles de pare-feu.
Récupération : réappliquez les règles nécessaires et assurez-vous qu'elles sont enregistrées. Vérifiez l'ordre des règles avec iptables -L -n -v pour voir si certaines bloquent les chaînes de Docker.
Sous-réseaux qui se chevauchent
Pourquoi cela arrive : vous créez un réseau personnalisé avec un sous-réseau qui chevauche le LAN de l'hôte ou un autre réseau, ce qui entraîne des conflits de routage. Le trafic destiné à des hôtes externes peut être acheminé vers le pont Docker.
Comment éviter : choisissez une plage IP privée qui n'est pas utilisée ailleurs dans votre infrastructure. Utilisez docker network inspect pour examiner les réseaux existants avant d'en créer un nouveau.
Récupération : supprimez le réseau conflictuel et recréez-le avec un sous-réseau non chevauchant. Assurez-vous que les conteneurs sont rattachés et retestés.
Ne pas vérifier le support IPv6
Pourquoi cela arrive : votre conteneur ou votre application tente de résoudre une adresse IPv6, mais le démon Docker ou l'hôte n'a pas IPv6 activé. La connexion se bloque ou échoue.
Comment éviter : sachez si IPv6 est requis pour vos services. Si ce n'est pas le cas, désactivez IPv6 dans le conteneur ou utilisez un réseau IPv4 uniquement. Si nécessaire, activez IPv6 dans la configuration du démon Docker et utilisez un réseau compatible IPv6.
Récupération : vérifiez le /etc/resolv.conf du conteneur et le comportement de l'application. Si IPv6 n'est pas pris en charge, forcez IPv4 en ajustant l'application ou en utilisant --sysctl net.ipv6.conf.all.disable_ipv6=1 (bien que cela puisse avoir des effets secondaires).
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle pour le dépannage courant et la prévention.
| Étape | Action | Commande / Attente |
|---|---|---|
| 1 | Confirmer le contexte actif | docker context ls - assurez-vous que le bon contexte a * |
| 2 | Vérifier la connectivité au démon | docker info - renvoie les détails du démon |
| 3 | Lister les réseaux | docker network ls - notez les pilotes et les noms |
| 4 | Inspecter les paramètres réseau du conteneur | docker inspect <conteneur> -f '{{json .NetworkSettings}}' - vérifiez l'IP, les ports, le DNS |
| 5 | Tester le DNS depuis le conteneur | docker exec <conteneur> nslookup example.com - devrait résoudre |
| 6 | Tester la connectivité sortante | docker exec <conteneur> ping -c 4 8.8.8.8 - devrait recevoir des réponses |
| 7 | Tester le port entrant | curl http://localhost:<port-publié> sur l'hôte |
| 8 | Vérifier les règles du pare-feu | sudo ufw status ou sudo iptables -L -n |
| 9 | Examiner les journaux | docker logs <conteneur> - cherchez les erreurs liées au réseau |
| 10 | Documenter les modifications | Gardez des notes sur toute modification pour un retour en arrière futur |
Effectuez cette liste de contrôle lors de l'investigation de tout problème réseau, et après avoir appliqué des correctifs pour confirmer la résolution.
Conclusion
Les problèmes réseau des contextes Docker peuvent être difficiles, mais une approche structurée les rend gérables. Commencez par inventorier votre environnement et comprendre le contexte et la topologie du réseau. Effectuez des modifications sûres et limitées pour les tests, puis vérifiez systématiquement chaque couche : réseau du conteneur, DNS, sortant et entrant. Lorsque des défaillances surviennent, utilisez les étapes de récupération pour revenir en arrière ou corriger. Enfin, maintenez une liste de contrôle opérationnelle pour un dépannage reproductible. Avec ces pratiques, vous pouvez rapidement diagnostiquer et résoudre les problèmes de connectivité sur n'importe quel contexte Docker.
N'oubliez pas de toujours tester de manière contrôlée, de documenter vos modifications et de vérifier après chaque étape. Cela réduit les temps d'arrêt et renforce la confiance dans vos déploiements Docker.