## Introduction

Le réseautage Docker est une source fréquente de frustration dans les environnements conteneurisés. Un conteneur qui ne peut pas atteindre sa base de données, un service qui ne peut pas résoudre un autre service par son nom, ou un mappage de port qui refuse de fonctionner peut interrompre le développement et perturber la production. Cet article se concentre sur les erreurs de réseautage Docker courantes et fournit des correctifs pratiques avec des exemples concrets. Il s'adresse aux développeurs, aux consultants DevOps et aux équipes techniques de startups qui doivent passer rapidement d'un problème observé à un résultat vérifié.

Nous couvrirons les modes de défaillance les plus courants, notamment les mauvaises configurations de réseaux bridge, les problèmes de réseaux overlay dans Swarm, les échecs de résolution DNS, les problèmes de publication de ports et les incidents IPv6. Pour chacun, nous montrons comment diagnostiquer le problème à l'aide des commandes Docker standard, comprendre la cause première, appliquer le correctif minimal sûr et vérifier le résultat. L'objectif est la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets et documenter les étapes de récupération.

Tout au long de l'article, nous insistons sur une approche systématique :

- **Inventorier l'environnement** : connaître la version de Docker, la topologie et l'état actuel.
- **Diagnostics en lecture seule** : utiliser `docker network inspect`, `docker logs`, `docker exec` et d'autres commandes pour recueillir des preuves.
- **Changement minimal** : ajuster un élément de configuration ciblé à la fois.
- **Vérifier** : confirmer le correctif avec une commande spécifique et une sortie attendue.

À la fin, vous disposerez d'un ensemble de procédures de dépannage reproductibles et d'une liste de contrôle pour prévenir les problèmes de réseau récurrents.

## Inventaire de la version et de l'environnement

Avant de plonger dans les correctifs, établissez une base de référence. Connaître votre version de Docker, le pilote de stockage, les plugins réseau et le runtime de conteneur vous aide à éviter d'appliquer des conseils destinés à une configuration différente. Exécutez les commandes suivantes et enregistrez la sortie :

```bash
# Version de Docker
$ docker version --format '{{.Server.Version}}'
24.0.7

# Informations Docker (concentrez-vous sur les sections pertinentes pour le réseau)
$ docker info --format '{{json .Plugins.Network}}'
["bridge","host","overlay","macvlan"]

# Lister les conteneurs en cours d'exécution avec leurs réseaux
$ docker ps --format 'table {{.Names}}	{{.Networks}}	{{.Ports}}'
NAMES               NETWORKS            PORTS
web                 bridge              0.0.0.0:8080->80/tcp
db                  myapp_default
```

Pour les projets Compose, utilisez `docker compose ps` et inspectez le réseau généré :

```bash
$ docker compose ps
NAME                COMMAND                  SERVICE             STATUS              PORTS
myapp_web_1         "docker-entrypoint.s…"   web                 running             0.0.0.0:8080->80/tcp
myapp_db_1          "docker-entrypoint.s…"   db                  running             5432/tcp

$ docker network ls | grep myapp
NETWORK ID     NAME           DRIVER    SCOPE
abc123def456   myapp_default  bridge    local
```

Si vous soupçonnez un problème de plugin réseau, listez tous les réseaux avec leurs pilotes et leur portée :

```bash
$ docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
1234567890ab   bridge    bridge    local
cdef12345678   host      host      local
90abcdef1234   none      null      local
```

Un test local de type production devrait inclure un test de redémarrage : arrêtez le conteneur, recréez-le et confirmez que l'application voit toujours le réseau et les fichiers attendus. Si la connectivité se rompt après un redémarrage, vous avez probablement une configuration qui dépend d'adresses IP de conteneur éphémères ou d'une définition de réseau manquante.

## Erreur courante 1 : le conteneur ne peut pas atteindre Internet ou les hôtes externes

### Symptôme

Un conteneur ne peut pas `ping` une IP externe (par exemple, 8.8.8.8) ou `curl` une URL publique. L'erreur peut être `ping: bad address` ou `curl: (6) Could not resolve host`, indiquant une défaillance DNS ou de routage.

### Diagnostic

Commencez par vérifier les paramètres réseau du conteneur :

```bash
$ docker exec mycontainer ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
```

Si le conteneur n'a pas d'IP ou si l'interface est désactivée, quelque chose ne va pas avec la création du réseau. Vérifiez l'attachement réseau du conteneur :

```bash
$ docker inspect --format '{{json .NetworkSettings.Networks}}' mycontainer
{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"1234567890ab","EndpointID":"","Gateway":"","IPAddress":"","IPPrefixLen":0,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"","DriverOpts":null}}
```

Une IPAddress vide suggère que le conteneur n'a pas rejoint correctement le réseau. Essayez de le connecter explicitement :

```bash
$ docker network connect bridge mycontainer
```

Si le conteneur n'a toujours pas de connectivité, inspectez les paramètres DNS du démon Docker. Le démon utilise le fichier `/etc/resolv.conf` de l'hôte par défaut, mais vous pouvez le remplacer :

```bash
$ docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "1234567890ab",
        "Created": "2024-01-01T00:00:00.000000000Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "...": {}
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
```

Si `"Internal": true`, le réseau est isolé du trafic externe. Si la résolution DNS échoue, vérifiez le fichier `/etc/resolv.conf` du conteneur :

```bash
$ docker exec mycontainer cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
```

Le serveur DNS intégré à 127.0.0.11 devrait être présent. Sinon, le conteneur a été démarré avec des options `--dns` ou `--dns-search` qui peuvent être incorrectes.

### Correctif

1. Si le conteneur est sur un réseau personnalisé avec `internal: true`, recréez le réseau sans ce drapeau ou connectez le conteneur à un réseau externe.
2. Si le DNS est mal configuré, démarrez le conteneur avec des serveurs DNS explicites :

   ```bash
   $ docker run -d --name mycontainer --dns 8.8.8.8 --dns 1.1.1.1 myimage
   ```

3. Si le réseau bridge par défaut cause des problèmes, créez un réseau bridge défini par l'utilisateur, qui fournit une résolution DNS automatique entre les conteneurs :

   ```bash
   $ docker network create mynet
   $ docker run -d --name mycontainer --network mynet myimage
   ```

4. Vérifiez la connectivité :

   ```bash
   $ docker exec mycontainer ping -c 4 8.8.8.8
   PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
   64 bytes from 8.8.8.8: icmp_seq=1 ttl=114 time=18.6 ms
   ...
   ```

## Erreur courante 2 : les conteneurs ne peuvent pas communiquer entre eux sur un réseau bridge défini par l'utilisateur

### Symptôme

Deux conteneurs sur le même réseau bridge défini par l'utilisateur ne peuvent pas se résoudre par leur nom ou se connecter via IP. Par exemple, un conteneur web ne peut pas atteindre `db` à `db:5432`.

### Diagnostic

Tout d'abord, confirmez que les deux conteneurs sont sur le même réseau :

```bash
$ docker network inspect mynet
[
    {
        "Name": "mynet",
        "Id": "...",
        "Containers": {
            "container1_id": {
                "Name": "web",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "container2_id": {
                "Name": "db",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        }
    }
]
```

Si un conteneur est manquant, connectez-le :

```bash
$ docker network connect mynet web
```

Vérifiez si les conteneurs peuvent se pinger par IP :

```bash
$ docker exec web ping -c 4 172.18.0.3
PING 172.18.0.3 (172.18.0.3) 56(84) bytes of data.
64 bytes from 172.18.0.3: icmp_seq=1 ttl=64 time=0.123 ms
...
```

Si le ping IP fonctionne mais que la résolution de nom échoue, testez avec `nslookup` ou `getent` :

```bash
$ docker exec web nslookup db
Server:         127.0.0.11
Address:        127.0.0.11#53

Name:   db
Address: 172.18.0.3
```

Si `nslookup` échoue, le serveur DNS intégré peut avoir des problèmes, ou le fichier `/etc/resolv.conf` du conteneur ne pointe pas vers 127.0.0.11.

Une erreur courante est d'utiliser le réseau bridge par défaut, qui ne fournit pas de résolution DNS automatique. Sur le bridge par défaut, les conteneurs ne peuvent communiquer que via des adresses IP (à moins d'utiliser `--link`, qui est obsolète).

### Correctif

1. Créez un réseau bridge défini par l'utilisateur et attachez-y les deux conteneurs :

   ```bash
   $ docker network create mynet
   $ docker network connect mynet web
   $ docker network connect mynet db
   ```

2. Alternativement, recréez les conteneurs avec le réseau spécifié au démarrage :

   ```bash
   $ docker run -d --name web --network mynet webimage
   $ docker run -d --name db --network mynet dbimage
   ```

3. Testez à nouveau la résolution de nom :

   ```bash
   $ docker exec web ping -c 1 db
   PING db (172.18.0.3) 56(84) bytes of data.
   64 bytes from db.mynet (172.18.0.3): icmp_seq=1 ttl=64 time=0.089 ms
   ```

## Erreur courante 3 : le mappage de port ne fonctionne pas ou le port est déjà utilisé

### Symptôme

Un conteneur est démarré avec `-p 8080:80`, mais l'accès à `localhost:8080` échoue, ou le conteneur ne démarre pas avec `Bind for 0.0.0.0:8080 failed: port is already allocated`.

### Diagnostic

Vérifiez si le port est déjà utilisé sur l'hôte :

```bash
$ sudo ss -tulpn | grep :8080
tcp   LISTEN 0      128          0.0.0.0:8080      0.0.0.0:*    users:(("docker-proxy",pid=1234,fd=4))
```

Un autre conteneur peut utiliser le même port. Listez les mappages de ports :

```bash
$ docker ps --format '{{.Names}}	{{.Ports}}'
web1                0.0.0.0:8080->80/tcp
web2                0.0.0.0:8080->80/tcp  # Ceci échouera au démarrage
```

Si vous utilisez un pare-feu, assurez-vous que le port est autorisé. Vérifiez également que le processus du conteneur écoute réellement sur le port du conteneur :

```bash
$ docker exec web1 netstat -tulpn | grep :80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1/nginx: master p
```

### Correctif

1. Utilisez un port hôte différent :

   ```bash
   $ docker run -d --name web2 -p 8081:80 webimage
   ```

2. Ou utilisez le mappage de port dynamique et interrogez le port attribué :

   ```bash
   $ docker run -d --name web2 -P webimage
   $ docker port web2
   80/tcp -> 0.0.0.0:49153
   ```

3. Si un port doit être libéré, identifiez et arrêtez le processus qui l'utilise, puis redémarrez le conteneur.

## Erreur courante 4 : problèmes de réseau overlay dans Docker Swarm

### Symptôme

Dans un cluster Swarm, les services sur différents nœuds ne peuvent pas communiquer via un réseau overlay. Des erreurs comme `No route to host` ou des échecs de résolution de nom se produisent.

### Diagnostic

Tout d'abord, assurez-vous que le réseau overlay existe et est attaché aux services :

```bash
$ docker network ls | grep overlay
NETWORK ID     NAME              DRIVER    SCOPE
xyz123abc456   myoverlay         overlay   swarm

$ docker service inspect --format '{{json .Spec.TaskTemplate.Networks}}' myservice
[{"Target":"xyz123abc456"}]
```

Vérifiez que tous les nœuds ont les ports nécessaires ouverts pour le réseautage overlay : TCP 2377 pour la gestion du cluster, TCP/UDP 7946 pour la communication entre nœuds et UDP 4789 pour les données VXLAN.

Sur chaque nœud, vérifiez que l'interface VXLAN existe :

```bash
$ ip link show type vxlan
10: vxlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UNKNOWN mode DEFAULT group default 
    link/ether 02:42:... brd ff:ff:ff:ff:ff:ff
```

Si l'interface VXLAN est manquante ou si le MTU est incorrect, cela peut causer des fragmentations et des problèmes de connectivité.

### Correctif

1. Assurez-vous que les règles de pare-feu autorisent les ports requis.
2. Si des problèmes de MTU sont suspectés, ajustez le MTU sur le démon Docker ou le réseau. Par exemple, si le réseau sous-jacent a un MTU de 1400, définissez le MTU Docker à 1400 :

   ```bash
   $ sudo dockerd --mtu 1400
   ```

   Ou définissez-le par réseau :

   ```bash
   $ docker network create -d overlay --opt com.docker.network.driver.mtu=1400 myoverlay
   ```

3. Redémarrez le démon Docker sur les nœuds affectés.

## Erreur courante 5 : échecs de résolution DNS pour les domaines personnalisés

### Symptôme

Un conteneur ne peut pas résoudre un domaine interne personnalisé, par exemple `api.internal.example.com`.

### Diagnostic

Vérifiez la configuration DNS du conteneur :

```bash
$ docker exec mycontainer cat /etc/resolv.conf
search mydomain.local
nameserver 127.0.0.11
options ndots:0
```

Si le domaine personnalisé est servi par un serveur DNS externe, le conteneur peut ne pas le consulter. Testez avec `nslookup` en utilisant le serveur spécifique :

```bash
$ docker exec mycontainer nslookup api.internal.example.com 10.0.0.53
```

Si cela fonctionne mais que la résolution par défaut ne fonctionne pas, le DNS Docker peut ne pas transférer vers le bon serveur.

### Correctif

Démarrez le conteneur avec les options `--dns` et `--dns-search` :

```bash
$ docker run -d --name mycontainer --dns 10.0.0.53 --dns 8.8.8.8 --dns-search mydomain.local myimage
```

Alternativement, configurez le démon Docker pour utiliser un serveur DNS personnalisé globalement en éditant `/etc/docker/daemon.json` :

```json
{
  "dns": ["10.0.0.53", "8.8.8.8"],
  "dns-search": ["mydomain.local"]
}
```

Puis redémarrez Docker :

```bash
$ sudo systemctl restart docker
```

## Erreur courante 6 : problèmes de configuration IPv6

### Symptôme

Les conteneurs ne reçoivent pas d'adresses IPv6 ou ne peuvent pas communiquer via IPv6.

### Diagnostic

Vérifiez si IPv6 est activé sur le réseau :

```bash
$ docker network inspect bridge | grep EnableIPv6
"EnableIPv6": false,
```

Par défaut, IPv6 est désactivé. Si vous avez besoin d'IPv6, vous devez l'activer dans la configuration du démon et créer des réseaux avec des sous-réseaux IPv6.

### Correctif

1. Éditez `/etc/docker/daemon.json` pour activer IPv6 et définir un CIDR fixe :

   ```json
   {
     "ipv6": true,
     "fixed-cidr-v6": "2001:db8:1::/64"
   }
   ```

2. Redémarrez Docker :

   ```bash
   $ sudo systemctl restart docker
   ```

3. Créez un réseau avec support IPv6 :

   ```bash
   $ docker network create --ipv6 --subnet=2001:db8:1::/64 myipv6net
   ```

4. Exécutez un conteneur sur ce réseau et vérifiez son adresse IPv6 :

   ```bash
   $ docker run -d --name ipv6test --network myipv6net alpine sleep 300
   $ docker exec ipv6test ip -6 addr show eth0
   2: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP 
       inet6 2001:db8:1::242:ac11:2/64 scope global nodad 
          valid_lft forever preferred_lft forever
   ```

## Pièges courants et comment les éviter

1. **Utiliser le réseau bridge par défaut pour la production**. Le bridge par défaut manque de découverte de service automatique et d'isolation. Créez toujours des réseaux définis par l'utilisateur pour les applications.
   - **Pourquoi cela arrive** : commodité ; `docker run` sans `--network` utilise par défaut le bridge.
   - **Comment éviter** : définissez les réseaux dans les fichiers Compose ou créez explicitement des réseaux personnalisés.

2. **Coder en dur les IP des conteneurs**. Les IP des conteneurs peuvent changer après recréation. Fiez-vous plutôt aux noms DNS.
   - **Pourquoi cela arrive** : les développeurs peuvent inspecter et copier les IP.
   - **Comment éviter** : utilisez les noms de service ; si nécessaire, attribuez des IP statiques via `--ip` sur un réseau défini par l'utilisateur.

3. **Ignorer les incompatibilités de MTU**. Les réseaux overlay sur VPN ou certains fournisseurs cloud peuvent nécessiter un MTU plus bas.
   - **Pourquoi cela arrive** : le MTU par défaut de 1500 peut ne pas fonctionner si le réseau sous-jacent a un MTU plus bas.
   - **Comment éviter** : testez avec `ping -M do -s 1472 <hôte>` pour découvrir le MTU maximum et configurez en conséquence.

4. **Ne pas nettoyer les réseaux inutilisés**. Les réseaux inutilisés peuvent encombrer l'environnement et causer de la confusion.
   - **Pourquoi cela arrive** : oublier de supprimer les réseaux après des expériences.
   - **Comment éviter** : exécutez périodiquement `docker network prune`.

5. **Négliger les règles de pare-feu**. Pour Swarm ou les configurations multi-hôtes, des ports de pare-feu manquants causent des échecs mystérieux.
   - **Pourquoi cela arrive** : supposer que tout le trafic est autorisé.
   - **Comment éviter** : documentez les ports requis et vérifiez avec `nc -zv <hôte> <port>`.

## Liste de contrôle opérationnelle

Utilisez cette liste de contrôle avant et après avoir apporté des modifications réseau :

- [ ] Enregistrer l'état actuel : `docker network ls`, `docker ps`, `docker info`.
- [ ] Identifier l'erreur : collecter les messages d'erreur exacts des journaux et des commandes.
- [ ] Isoler le problème : tester la connectivité avec `ping`, `curl`, `nslookup` et `traceroute`.
- [ ] Vérifier la configuration réseau : `docker network inspect <réseau>`.
- [ ] Vérifier les paramètres DNS : `cat /etc/resolv.conf` à l'intérieur du conteneur.
- [ ] Vérifier les mappages de ports : `docker port <conteneur>`.
- [ ] Vérifier les règles de pare-feu : assurez-vous que les ports requis sont ouverts.
- [ ] Apporter un seul changement à la fois et tester après chaque changement.
- [ ] Documenter le changement et le plan de retour en arrière.
- [ ] Vérifier le correctif : répéter la commande d'origine qui échouait et confirmer le succès.
- [ ] Mettre à jour la surveillance et les alertes si nécessaire.

## Conclusion

Les erreurs de réseau Docker peuvent être intimidantes, mais une approche systématique simplifie le dépannage. En établissant une base de référence, en utilisant les bonnes commandes de diagnostic, en comprenant les schémas de défaillance courants et en appliquant des correctifs minimaux avec vérification, vous pouvez résoudre rapidement la plupart des problèmes de réseau. Préférez toujours les réseaux bridge définis par l'utilisateur pour la communication conteneur à conteneur, évitez de coder en dur les IP et faites attention aux paramètres DNS et MTU. Utilisez la liste de contrôle opérationnelle pour prévenir les problèmes futurs et garantir un environnement de conteneurs fiable. Avec la pratique, vous naviguerez dans le réseautage Docker en toute confiance.