Introduction
Le réseau Docker est un outil puissant, mais c'est aussi l'une des sources les plus courantes d'incidents en production. Un réseau bridge mal configuré, un sous-réseau qui se chevauche ou un port publié incorrectement peuvent provoquer des pannes d'application, des échecs de connectivité et des vulnérabilités de sécurité. Ce guide présente des exemples pratiques d'erreurs de réseau Docker, explique pourquoi elles surviennent et montre comment les diagnostiquer, les corriger et les éviter.
Cet article s'adresse aux développeurs, ingénieurs DevOps, SRE et équipes techniques de startups qui utilisent Docker en développement, en préproduction ou en production. Il suppose que vous connaissez les commandes Docker de base et les concepts tels que les conteneurs, les images et Docker Compose, mais vous n'êtes peut-être pas un expert en réseau Linux ou en orchestration de conteneurs.
Vous apprendrez à :
- Réaliser un inventaire des versions et de l'environnement avant toute modification.
- Suivre un chemin de configuration sûr avec un rayon d'impact minimal.
- Utiliser des commandes de diagnostic pour vérifier la connectivité et la configuration réseau.
- Reconnaître les modes de défaillance courants et s'en remettre.
- Établir une liste de contrôle opérationnelle pour maintenir la santé de votre réseau Docker.
Chaque section comprend des commandes concrètes, les sorties attendues et des exemples pratiques. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés plutôt que des secrets, vérifier le résultat et documenter la procédure de récupération si l'état attendu n'est pas atteint.
Inventaire des versions et de l'environnement
Avant de toucher à toute configuration réseau Docker, vous devez savoir exactement avec quoi vous travaillez. Cela inclut la version de Docker, le système d'exploitation, le moteur d'exécution des conteneurs, les pilotes réseau utilisés et l'état actuel de vos conteneurs et réseaux.
Commencez par vérifier votre version de Docker. Les différentes versions ont des fonctionnalités réseau et des valeurs par défaut différentes. Par exemple, Docker 20.10 a introduit la prise en charge de la chaîne spéciale host-gateway dans les hôtes supplémentaires, et Docker 23.0 a modifié le comportement du réseau bridge par défaut à certains égards. Exécutez :
docker version
La sortie attendue comprend les versions client et serveur, par exemple :
Client: Docker Engine - Community
Version: 24.0.5
API version: 1.43
Go version: go1.20.6
Git commit: ced0996
Built: Fri Jul 21 15:21: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.6
Git commit: a61e2b4
Built: Fri Jul 21 15:20:08 2023
OS/Arch: linux/amd64
Experimental: false
Si vous utilisez Docker Desktop sur Mac ou Windows, le modèle réseau est différent car Docker s'exécute dans une machine virtuelle légère. La commande docker version fonctionnera toujours, mais sachez que le réseau hôte se comporte différemment sur ces plateformes.
Ensuite, listez les réseaux existants. Docker crée trois réseaux par défaut : bridge, host et none. Des réseaux personnalisés peuvent également exister, surtout si vous utilisez Docker Compose. Exécutez :
docker network ls
Exemple de sortie :
NETWORK ID NAME DRIVER SCOPE
9f904ee27bf3 bridge bridge local
95e74588f40d host host local
d5c7d2f0c48d none null local
Notez la colonne du pilote. Le pilote bridge est utilisé pour le réseau mono-hôte, overlay pour le multi-hôte (Swarm), et macvlan ou ipvlan pour les cas avancés. Si vous voyez un réseau avec un pilote que vous ne reconnaissez pas, enquêtez avant de continuer.
Maintenant, vérifiez quels conteneurs sont en cours d'exécution et à quels réseaux ils sont attachés :
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}\t{{.Networks}}"
L'espace réservé {{.Networks}} est disponible dans les versions récentes de Docker et affiche les noms des réseaux auxquels le conteneur est connecté. Si votre version de Docker ne le prend pas en charge, utilisez docker inspect sur les conteneurs individuels.
Pour une vue plus détaillée des paramètres réseau d'un conteneur spécifique, utilisez :
docker inspect <nom_ou_id_du_conteneur>
Cela renvoie un objet JSON avec une section NetworkSettings qui inclut les adresses IP, la passerelle, l'adresse MAC, les ports et les noms de réseau. Par exemple, pour obtenir l'adresse IP d'un conteneur connecté à un réseau bridge personnalisé :
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mon_conteneur
La sortie attendue pourrait être 172.18.0.2. Notez que l'adresse IP est attribuée à partir du sous-réseau du réseau.
Enfin, si vous utilisez Docker Compose, vérifiez l'état du projet :
docker compose ps
Cela montre les services, leur état et les ports qu'ils publient. Exemple :
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
myapp_web_1 nginx:alpine "/docker-entrypoint.…" web 2 hours ago Up 2 hours 0.0.0.0:8080->80/tcp
myapp_db_1 postgres:15 "docker-entrypoint.s…" db 2 hours ago Up 2 hours 5432/tcp
Vous avez maintenant une image claire de l'environnement. Enregistrez ces informations dans un journal ou un runbook avant toute modification. Cela vous aidera à détecter les dérives et à revenir en arrière si nécessaire.
Piège : supposer que le réseau bridge par défaut est suffisant. De nombreux développeurs utilisent le réseau bridge par défaut pour tous les conteneurs. Cependant, sur le bridge par défaut, les conteneurs ne peuvent communiquer que par adresse IP, pas par nom, sauf si vous utilisez l'option --link (qui est obsolète et déconseillée). Cela conduit à des IP codées en dur et à des configurations fragiles. Au lieu de cela, créez toujours un réseau bridge personnalisé pour votre pile d'applications. Nous aborderons cela dans la section suivante.
Chemin de configuration sûr
Lorsque vous devez modifier la configuration réseau Docker, suivez un chemin sûr qui minimise les risques et permet un retour arrière rapide. Ce chemin implique d'observer l'état actuel, de planifier un changement minimal, de l'appliquer de manière réversible et de vérifier le résultat.
Étape 1 : Identifier le changement requis
Avant de créer ou de modifier un réseau, listez tous les conteneurs qui seront affectés. Par exemple, si vous devez déplacer un conteneur du bridge par défaut vers un réseau bridge personnalisé, assurez-vous qu'aucun autre conteneur ne dépend de l'adresse IP ou du nom DNS actuel.
Si vous utilisez Docker Compose, examinez le fichier docker-compose.yml. Une définition de service typique peut ressembler à ceci :
version: '3.8'
services:
web:
image: nginx:alpine
ports:
- "8080:80"
networks:
- frontend
db:
image: postgres:15
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
Dans cet exemple, le service web est sur le réseau frontend, et le service db est sur le réseau backend. Ils ne peuvent pas communiquer car ils sont sur des réseaux différents. Si vous avez besoin que le service web accède à la base de données, vous devez attacher les deux services à un réseau commun ou créer une connexion entre les réseaux.
Étape 2 : Créer un réseau bridge personnalisé
Au lieu de modifier les réseaux existants, créez-en un nouveau avec un nom descriptif et un sous-réseau spécifique pour éviter les conflits. Utilisez la commande docker network create avec des options explicites :
docker network create \
--driver bridge \
--subnet 172.28.0.0/16 \
--gateway 172.28.0.1 \
monapp_reseau
Sortie attendue : l'ID du réseau, par exemple f7b3c1d9e4a5...
Vérifiez que le réseau a été créé :
docker network inspect monapp_reseau
Vous devriez voir le sous-réseau et la passerelle dans la section IPAM, et un objet Containers vide jusqu'à ce que vous attachiez des conteneurs.
Étape 3 : Attacher un conteneur en cours d'exécution au réseau
Vous pouvez attacher un conteneur en cours d'exécution à un nouveau réseau sans l'arrêter en utilisant docker network connect. Cependant, soyez prudent car cela ajoute une nouvelle interface réseau au conteneur, ce qui peut affecter le routage ou provoquer des conflits si le conteneur a des routes statiques.
Exemple :
docker network connect monapp_reseau mon_conteneur
Pour vérifier, inspectez les réseaux du conteneur :
docker inspect -f '{{range $key, $value := .NetworkSettings.Networks}}{{$key}} {{end}}' mon_conteneur
Sortie attendue : bridge monapp_reseau (en supposant que le conteneur soit également sur le bridge par défaut).
Si vous devez déconnecter d'un réseau :
docker network disconnect monapp_reseau mon_conteneur
Cela est utile pour le retour arrière.
Étape 4 : Utiliser Compose pour des changements déclaratifs
Si votre application utilise Docker Compose, modifiez le fichier docker-compose.yml pour définir les réseaux et attacher les services. Ensuite, exécutez :
docker compose up -d
Compose créera les réseaux qui n'existent pas et attachera les conteneurs en conséquence. Pour appliquer des modifications à une pile existante, exécutez docker compose up -d --force-recreate pour recréer les conteneurs avec les nouveaux paramètres réseau. Sachez que cela entraînera une interruption de service pour ces conteneurs ; planifiez en conséquence.
Pour annuler une modification Compose, revenez à la version précédente du fichier docker-compose.yml et exécutez à nouveau docker compose up -d. L'utilisation d'un contrôle de version pour les fichiers Compose facilite cette opération.
Étape 5 : Vérifier la connectivité
Après avoir appliqué la modification, testez la connectivité entre les conteneurs. Par exemple, si vous avez attaché un conteneur web à un réseau avec une base de données, testez depuis l'intérieur du conteneur web :
docker exec -it web_container ping db_container
Si la résolution DNS fonctionne sur le réseau personnalisé, le ping devrait réussir. Vous pouvez également tester une connexion TCP en utilisant nc ou curl si disponible dans le conteneur.
Si le test échoue, vérifiez la configuration DNS du conteneur :
docker exec web_container cat /etc/resolv.conf
Sur un réseau bridge personnalisé, le serveur DNS intégré de Docker à 127.0.0.11 devrait être la première entrée. Si ce n'est pas le cas, votre conteneur pourrait ne pas résoudre les noms des autres conteneurs.
Piège : changer le sous-réseau du bridge par défaut sans considérer les conteneurs existants. Le réseau bridge par défaut utilise 172.17.0.0/16 par défaut. Certains administrateurs le modifient dans la configuration du démon Docker pour éviter les conflits avec les réseaux d'entreprise. Cependant, les conteneurs existants sur l'ancien sous-réseau perdront la connectivité s'ils ne sont pas recréés. Si vous devez modifier le sous-réseau du bridge par défaut, arrêtez tous les conteneurs, modifiez /etc/docker/daemon.json, redémarrez Docker, puis recréez les conteneurs. Il s'agit d'une opération à fort impact qui ne devrait être effectuée que pendant une fenêtre de maintenance.
Vérification et diagnostics
Après avoir apporté des modifications réseau, vous devez vérifier que tout fonctionne comme prévu et diagnostiquer les problèmes éventuels. Docker fournit plusieurs outils intégrés pour le débogage réseau.
Vérifier la résolution DNS des conteneurs
Comme mentionné précédemment, les réseaux bridge personnalisés fournissent une résolution DNS automatique entre les conteneurs en utilisant leurs noms. Pour tester depuis l'intérieur d'un conteneur, utilisez ping ou nslookup si disponible. Par exemple :
docker exec -it conteneur_a ping conteneur_b
Sortie attendue (partielle) :
PING conteneur_b (172.28.0.3): 56 data bytes
64 bytes from 172.28.0.3: seq=0 ttl=64 time=0.089 ms
Si le conteneur n'a pas ping, utilisez getent :
docker exec conteneur_a getent hosts conteneur_b
Sortie attendue : 172.28.0.3 conteneur_b
Si le DNS échoue, vérifiez le paramètre enable_ipv6 du réseau ou le fichier /etc/hosts du conteneur pour des entrées statiques qui pourraient outrepasser le DNS de Docker.
Inspecter les détails du réseau
Utilisez docker network inspect pour voir la configuration du réseau, y compris le sous-réseau, la passerelle, les conteneurs attachés et leurs adresses IP. Par exemple :
docker network inspect monapp_reseau
Recherchez des anomalies telles que des sous-réseaux qui se chevauchent, des conteneurs manquants ou des options de pilote incorrectes.
Tester la publication de ports
Si vous publiez des ports d'un conteneur vers l'hôte, vérifiez que le port est accessible de l'extérieur. Exécutez un serveur HTTP simple dans un conteneur :
docker run -d --name web -p 8080:80 nginx:alpine
Vérifiez depuis l'hôte :
curl http://localhost:8080
Vous devriez voir la page d'accueil Nginx par défaut en HTML. Sinon, vérifiez les journaux du conteneur :
docker logs web
Les erreurs possibles incluent « Address already in use » si le port de l'hôte est déjà pris. Utilisez ss -tulpn | grep 8080 sur Linux pour voir quel processus utilise le port.
Déboguer les réseaux overlay
Si vous utilisez Docker Swarm avec des réseaux overlay, vous avez besoin de vérifications supplémentaires. Utilisez docker network inspect pour voir le VIP du réseau overlay et les IP des pairs. Pour tester la découverte de services, exécutez dans un conteneur de tâche et faites un ping au nom du service :
docker exec -it <id_conteneur_tache> ping mon_service
Si le ping échoue, vérifiez les paramètres de chiffrement du réseau overlay et assurez-vous que les ports nécessaires (par exemple, 4789 UDP pour VXLAN) sont ouverts entre les nœuds Swarm.
Piège : utiliser localhost à l'intérieur d'un conteneur pour accéder à un autre conteneur. Dans Docker, localhost fait référence au conteneur lui-même, pas à l'hôte ni aux autres conteneurs. Si vous devez accéder à un service dans un autre conteneur, utilisez le nom du service (s'il est sur le même réseau) ou l'adresse IP de l'hôte avec le port publié. Pour l'accès à l'hôte depuis l'intérieur d'un conteneur, vous pouvez utiliser le nom DNS spécial host.docker.internal sur Docker Desktop, ou l'adresse IP de l'hôte sur Linux.
Modes de défaillance et récupération
Même avec une planification minutieuse, le réseau Docker peut échouer de manière inattendue. Cette section couvre les modes de défaillance courants, leurs symptômes et les étapes de récupération.
Défaillance 1 : Épuisement des adresses IP
Symptôme : Les nouveaux conteneurs ne peuvent pas obtenir d'adresse IP. Vous pouvez voir des erreurs telles que « failed to allocate IP address » dans les journaux des conteneurs ou la sortie de docker run.
Cause : Le sous-réseau du réseau n'a plus d'adresses IP libres. Par exemple, un petit sous-réseau comme /29 (seulement 6 adresses utilisables) peut être épuisé.
Récupération :
- Vérifiez le sous-réseau du réseau et les allocations actuelles :
docker network inspect monapp_reseau --format '{{json .IPAM.Config}}'
docker network inspect monapp_reseau --format '{{range .Containers}}{{.Name}} {{.IPv4Address}}{{"\n"}}{{end}}'
- Si possible, étendez le sous-réseau en créant un nouveau réseau avec un sous-réseau plus grand et en y déplaçant les conteneurs. Sinon, réduisez le nombre de conteneurs ou utilisez un sous-réseau plus grand dès le départ.
Défaillance 2 : Conflit de port
Symptôme : Le conteneur ne démarre pas avec l'erreur « Bind for 0.0.0.0:8080 failed: port is already allocated. »
Cause : Un autre processus sur l'hôte ou un autre conteneur utilise déjà le même port.
Récupération :
- Trouvez le processus en conflit :
ss -tulpn | grep 8080sur Linux, ounetstat -ano | findstr 8080sur Windows. - Soit arrêtez le processus en conflit, soit changez le port de l'hôte dans votre commande
docker runou votre fichier Compose. - Pour les conteneurs qui n'ont pas besoin de publier le port sur l'hôte, supprimez l'option
-pou utilisez--exposeà la place.
Défaillance 3 : Échec de la résolution DNS
Symptôme : Les conteneurs ne peuvent pas résoudre les noms de service, mais le ping par adresse IP fonctionne.
Cause : Le conteneur n'est pas connecté au réseau attendu, ou le serveur DNS intégré ne fonctionne pas.
Récupération :
- Vérifiez sur quels réseaux se trouve le conteneur :
docker inspect -f '{{range .NetworkSettings.Networks}}{{.NetworkID}} {{end}}' nom_conteneur. - Comparez avec les réseaux du conteneur cible. S'ils ne partagent pas un réseau commun, connectez-le :
docker network connect monapp_reseau nom_conteneur. - Vérifiez le fichier
/etc/resolv.confdu conteneur pour le serveur DNS de Docker127.0.0.11. - Si vous utilisez un DNS personnalisé, assurez-vous qu'il peut résoudre les noms Docker ou désactivez-le pour ce conteneur.
Défaillance 4 : Problèmes de connectivité du réseau overlay dans Swarm
Symptôme : Les services sur différents nœuds Swarm ne peuvent pas communiquer via un réseau overlay.
Cause : Règles de pare-feu bloquant le trafic VXLAN (port UDP 4789), paramètres de chiffrement incompatibles ou décalage d'horloge entre les nœuds.
Récupération :
- Vérifiez les règles de pare-feu sur tous les nœuds Swarm et ouvrez le port UDP 4789 (et TCP/UDP 7946 pour le plan de contrôle) si nécessaire.
- Vérifiez les paramètres de chiffrement :
docker network inspect mon_overlay --format '{{json .Options}}'recherche{"encrypted":"true"}. - Redémarrez Docker sur les nœuds affectés ou recréez le réseau overlay.
Piège : supposer que le retour arrière est toujours possible. Certaines modifications réseau, comme le changement du sous-réseau d'un réseau existant, ne sont pas directement réversibles sans recréer le réseau. Sauvegardez toujours vos fichiers de configuration (comme daemon.json, docker-compose.yml) et notez l'état actuel du réseau avant de faire des modifications. Utilisez le contrôle de version pour l'infrastructure en tant que code.
Liste de contrôle opérationnelle
Maintenir un réseau Docker sain nécessite des vérifications régulières et une gestion proactive. Voici une liste de contrôle opérationnelle que vous pouvez adopter et adapter. Chaque élément a un propriétaire ou une fréquence, mais vous devez attribuer une seule personne responsable pour chaque tâche dans votre équipe.
Audit réseau mensuel (Propriétaire : Ingénieur infrastructure - par exemple, Priya Shah)
- [ ] Lister tous les réseaux Docker et vérifier qu'ils sont nécessaires :
docker network ls. - [ ] Supprimer les réseaux inutilisés :
docker network prune(à utiliser avec prudence ; cela supprime tous les réseaux non utilisés par au moins un conteneur). - [ ] Vérifier les chevauchements de sous-réseaux entre les réseaux Docker et les réseaux d'entreprise. Documenter le plan de sous-réseaux.
- [ ] Examiner la publication des ports pour les conteneurs. S'assurer que seuls les ports nécessaires sont exposés à l'hôte. Utiliser
docker ps --format '{{.Names}} {{.Ports}}'. - [ ] Vérifier que les conteneurs qui doivent communiquer sont sur le même réseau personnalisé ou ont des routes appropriées.
Revue de sécurité trimestrielle (Propriétaire : Ingénieur sécurité - par exemple, Marcus Chen)
- [ ] Vérifier les capacités des conteneurs liées au réseau :
docker inspect --format '{{.HostConfig.CapAdd}}' nom_conteneur; supprimerNET_ADMINsauf nécessité absolue. - [ ] Examiner les politiques réseau : certains conteneurs utilisent-ils le réseau
host? Si oui, justifier et documenter le risque. - [ ] Scanner les API Docker exposées : s'assurer que le démon Docker n'écoute pas sur un port public sans TLS.
Après chaque changement d'infrastructure (Propriétaire : Ingénieur d'astreinte - rotation hebdomadaire)
- [ ] Exécuter
docker network inspect <nom_reseau>sur les réseaux critiques pour vérifier le sous-réseau, la passerelle et les conteneurs attachés. - [ ] Tester la connectivité entre les services principaux en utilisant
pingoucurldepuis l'intérieur des conteneurs. - [ ] Vérifier les journaux pour les erreurs liées au réseau :
journalctl -u docker(sur les systèmes systemd) ou les journaux du démon Docker.
Surveillance continue (Propriétaire : Équipe de surveillance - revue mensuelle)
- [ ] Configurer des alertes pour une latence réseau élevée ou une perte de paquets dans les conteneurs en utilisant des outils comme Prometheus et cAdvisor.
- [ ] Surveiller les événements du démon Docker pour les actions de création/connexion/déconnexion de réseau :
docker events --filter 'type=network'. - [ ] Garder les versions de Docker à jour, mais tester les changements réseau en préproduction avant la production.
En suivant cette liste de contrôle, vous pouvez détecter de nombreux problèmes réseau avant qu'ils ne provoquent des pannes.
Conclusion
Les erreurs de configuration réseau Docker sont courantes, mais elles sont également évitables avec une planification minutieuse, de l'observation et des tests. Ce guide a couvert les étapes essentielles : inventorier votre environnement, suivre un processus de changement sûr, vérifier votre configuration, comprendre les modes de défaillance courants et maintenir une liste de contrôle opérationnelle régulière.
Rappelez-vous ces points clés :
- Créez toujours des réseaux bridge personnalisés pour les conteneurs d'application afin d'activer la résolution DNS et l'isolation.
- Utilisez des sous-réseaux explicites pour éviter les conflits d'adresses IP.
- Publiez uniquement les ports nécessaires vers l'hôte.
- Testez la connectivité après chaque modification.
- Documentez votre architecture réseau et conservez les fichiers de configuration dans un contrôle de version.
- Attribuez la responsabilité des vérifications de santé et des revues du réseau.
Comme prochaine étape, choisissez une vérification à faible risque de ce guide, comme l'inspection du sous-réseau d'un réseau ou le test de la résolution DNS entre deux conteneurs. Exécutez la commande, enregistrez la sortie et comparez-la avec le résultat attendu. Ensuite, ajoutez un audit réseau mensuel à votre calendrier opérationnel.
Un flux de travail technique fiable rend les défaillances visibles, protège les valeurs sensibles, limite les modifications à la ressource prévue et définit la vérification de récupération avant qu'un incident ne force la décision.