## 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 :

```bash
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 :

```bash
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 :

```bash
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.

```bash
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 :

```bash
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 :

```bash
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é :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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é :

```bash
curl http://localhost:8080
```

Si cela échoue, vérifiez que le conteneur est en cours d'exécution et qu'il écoute :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 :

```bash
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 vers `127.0.0.11` ou un DNS externe valide.
- Vérifiez que la résolution DNS de l'hôte fonctionne (`nslookup example.com` sur 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.1` au lieu de `0.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 affiche `127.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 8080` sur 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 testnet` pour 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.