Comprendre le réseau sous Docker 1/2 : le Bridge

Ceci est le premier article sur la gestion du réseau sous Docker. Dans ce post, nous allons  découvrir  ensemble comment sont connectés nos conteneurs sur le réseau, créer des réseaux et utiliser ces réseaux pour nos conteneurs.

1- Le réseau ponte ou le Bridge docker0

Lors de l’installation de Docker, trois réseaux sont créés automatiquement. On peut voir ces réseaux avec la commande docker network ls. Un réseau de type bridge est créé :

#docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
32cd2d55155f        bridge              bridge              local
b7fe5d1b69a7        host                host                local
de5ae709fdcd        none                null                local

Le réseau Bridge est présent sur tous les hôtes Docker. Lors de la création d’un conteneur, si l’on ne spécifie pas un réseau particulier, les conteneurs sont connectés au Bridge docker0.

La commande ifconfig ou ip a fournit les informations sur le réseau ponté (bridge).

$ ifconfig

docker0   Link encap:Ethernet  HWaddr 02:42:47:bc:3a:eb
          inet addr:172.17.0.1  Bcast:0.0.0.0  Mask:255.255.0.0
          inet6 addr: fe80::42:47ff:febc:3aeb/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:9001  Metric:1
          RX packets:17 errors:0 dropped:0 overruns:0 frame:0
          TX packets:8 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:1100 (1.1 KB)  TX bytes:648 (648.0 B)

La commande docker network inspect bridge, retourne les informations concernant ce réseau :

#docker network inspect bridge

[
   {
       "Name": "bridge",
       "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
       "Scope": "local",
       "Driver": "bridge",
       "IPAM": {
           "Driver": "default",
           "Config": [
               {
                   "Subnet": "172.17.0.1/16",
                   "Gateway": "172.17.0.1"
               }
           ]
       },
       "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": "9001"
       },
       "Labels": {}
   }
]

Créons deux containers avec l’image alpine.

# docker run -itd --name=container1 alpine

3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c

# docker run -itd --name=container2 alpine

94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c

Et visualisons les informations du réseau avec docker network inspect :

# docker network inspect bridge

{[
    {
        "Name": "bridge",
        "Id": "f7ab26d71dbd6f557852c7156ae0574bbf62c42f539b50c8ebde0f728a253b6f",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.17.0.1/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Containers": {
            "3386a527aa08b37ea9232cbcace2d2458d49f44bb05a6b775fba7ddd40d8f92c": {
                "EndpointID": "647c12443e91faf0fd508b6edfe59c30b642abb60dfab890b4bdccee38750bc1",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "94447ca479852d29aeddca75c28f7104df3c3196d7b6d83061879e339946805c": {
                "EndpointID": "b047d090f446ac49747d3c37d63e4307be745876db7f0ceef7b311cbba615f48",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "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": "9001"
        },
        "Labels": {}
    }
]

Les conteneurs sont connectés au Bridge par défaut docker0 et peuvent communiquer entre eux par adresse IP, les conteneurs se trouvent alors, sur le même réseau.

Docker ne prend pas en charge la découverte automatique du service sur le réseau Bridge par défaut. Afin que les conteneurs puissent résoudre les adresses IP par les noms d’hôte des conteneurs on crée des réseaux définis par l’utilisateur.

On peut aussi lier deux conteneurs à l’aide de l’option Legacy docker run –link, mais cela n’est pas recommandé.

2- Réseaux définis par l’utilisateur

Il est recommandé d’utiliser des réseaux Bridgés définis par l’utilisateur pour contrôler quels conteneurs peuvent communiquer entre eux, et ansi permettre la résolution DNS des noms d’hôtes des conteneurs avec les adresses IP.

Docker fournit des pilotes  pour créer ces réseaux. Réseau Bridgé, réseau overlay (Multihost) ou un réseau MACVLAN (Overlay et MacVlan seront vu dans de prochains articles). On peut également créer des plugins réseau ou utiliser un réseau distant. La libraire réseau de Docker , libnetwork (un article sera également consacré a la libnetwork prochainement) peut agir comme un proxy pour des plugins distant, remote driver.

Le réseau ponté ou Bridgé est le réseau par défaut lors de la création de nouveaux réseaux.

On peut  créer autant de réseaux que l’on souhaite et on peut connecter un conteneur à zéro ou plus de ces réseaux à tout moment. On peut également, connecter et déconnecter des conteneurs en cours d’exécution des réseaux sans redémarrer ces deniers.

Réseaux Bridgés

Un réseau Bridgé est le type de réseau le plus utilisé dans Docker. Les réseaux Bridgés créés par les utilisateurs sont semblables au réseau bridge par défaut créé à l’installation de Docker Docker0. Cependant de nouvelles fonctionnalités sont ajoutées, la gestion du DNS par exemple. Lors de la création de nouveau réseau, une nouvelle interface est créée. Cette interface est pontée :

# brctl show
br-2c601356b5d5        8000.0242b41afdcb    no        vetha2743d6
docker0                8000.0242fbdce780    no        veth46fbe31

Création d’un réseau Bridge Blue
# docker network create --driver bridge blue

1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b

# docker network inspect blue
[
    {
        "Name": "blue",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

# docker network ls

NETWORK ID          NAME                DRIVER
9f904ee27bf5        none                null
cf03ee007fb4        host                host
7fca4eb8c647        bridge              bridge
c5ee82f76de3        blue                bridge

Connexion d’un container au réseau blue

# docker run --network blue -itd --name blue1 alpine

8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c

# docker network inspect blue
[
    {
        "Name": "blue",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c": {
                "EndpointID": "93b2db4a9b9a997beb912d28bcfc117f7b0eb924ff91d48cfa251d473e6a9b08",
                "MacAddress": "02:42:ac:15:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

Connexion d’un container au réseau blue

# docker run -itd --name blue2 alpine 8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c

# docker network connect blue blue2

# docker network inspect blue
[
    {
        "Name": "blue",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {}
            ]
        },
        "Containers": {
            "8c1a0a5be480921d669a073393ade66a3fc49933f08bcc5515b37b8144f6d47c": {
                "EndpointID": "93b2db4a9b9a997beb912d28bcfc117f7b0eb924ff91d48cfa251d473e6a9b08",
                "MacAddress": "02:42:ac:15:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]
Serveur DNS intégré

Docker daemon exécute un serveur DNS intégré qui fournit une résolution de noms aux conteneurs connectés au réseau créé par les utilisateurs, de sorte que ces conteneurs peuvent résoudre les noms de d’hôtes en adresses IP.

Si le serveur DNS intégré est incapable de résoudre la demande, il sera transmis à tous les serveurs DNS externes configurés pour le conteneur. Pour faciliter cela lorsque le conteneur est créé, seul le serveur DNS intégré 127.0.0.11 est renseigné dans le fichier resolv.conf du conteneur.

Testons le serveur DNS intégré :

# docker network create --driver bridge blue
1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b

# docker network inspect blue

[
    {
        "Name": "blue",
        "Id": "1196a4c5af43a21ae38ef34515b6af19236a3fc48122cf585e3f3054d509679b",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1/16"
                }
            ]
        },
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

# docker run -it --name blue1 --network blue debian /bin/bash

# docker run -it --name blue2 --network blue debian /bin/bash

# docker network inspect blue 
[
    {
        "Name": "blue",
        "Id": "2c601356b5d51f3044518bca70c5bc016b2e0a0ccb28475a098185d831c4f27c",
        "Created": "2017-06-07T12:50:24.911280255+02:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Containers": {
            "1d105c8c8ab5e84c5cc0e7fac6c57946acc3501c2e9ac202d4a1709a3ab6bd26": {
                "Name": "blue1",
                "EndpointID": "47d0c1a4041b76123ccfa16a94a2a4211b56c1255c52d670091b8dedcf15241c",
                "MacAddress": "02:42:ac:12:00:02",
                "IPv4Address": "172.18.0.2/16",
                "IPv6Address": ""
            },
            "feb6d086c7813c621218bed5bda2436cc039c7e30f88e04b39ec669bd95f530c": {
                "Name": "blue2",
                "EndpointID": "cf2c8d36398b0b73920c522efaa3f4c22aa81e02053d882998b3d9d271fe4f11",
                "MacAddress": "02:42:ac:12:00:03",
                "IPv4Address": "172.18.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {},
        "Labels": {}
    }
]

# docker attach blue2
root@1d105c8c8ab5:/#
root@feb6d086c781:/# apt-get install dnsutils

root@feb6d086c781:/# dig

; <<>> DiG 9.9.5-9+deb8u11-Debian <<>>
;; global options: +cmd
......
.            119855    IN    NS    k.root-servers.net.
.            119855    IN    NS    l.root-servers.net.
.            119855    IN    NS    m.root-servers.net.

;; Query time: 64 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Thu Jun 08 08:02:44 UTC 2017
;; MSG SIZE  rcvd: 239


dig blue1

; <<>> DiG 9.9.5-9+deb8u11-Debian <<>> blue1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 63460
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;blue1.                IN    A

;; ANSWER SECTION:
blue1.            600    IN    A    172.18.0.2

;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Thu Jun 08 08:03:21 UTC 2017
;; MSG SIZE  rcvd: 44

root@feb6d086c781:/# cat /etc/resolv.conf 
nameserver 127.0.0.11
options ndots:0

Nos conteneurs sont maintenant connectés au réseau blue et peuvent discuter via les nom d’hôtes. Mais comment accède t’on à ces derniers à partir d’un réseau externe. Le réseau blue est un réseau privé.

Pour plus de maîtrise de Docker, vous pouvez suivre la formation Docker suivante sur Alphorm :

On voit tout cela dans le prochain article 🙂

5 pensées sur “Comprendre le réseau sous Docker 1/2 : le Bridge

  1. Tweety Répondre

    Bonjour,

    Très bon article, mais il y a un point que je ne comprends pas : est-ce que le serveur dns intégré est censé pouvoir résoudre des adresses externes ?

    J’essaie ceci mais ça ne marche pas

    docker network create mynetwork
    docker run -it –network mynetwork busybox ping -c 1 http://www.google.com

    Que faut-il faire pour que ça marche ?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.