Par défaut Docker propose 3 types de réseaux chacun ayant un driver dédié et des caractéristiques spécifiques.
docker network list NETWORK ID NAME DRIVER SCOPE 5c5d31d57162 bridge bridge local 89092ed731fa host host local 5f36f3d8495b none null local
A sa création, le conteneur rejoint un de ces 3 types de réseaux:
Le conteneur est intégré directement dans la pile réseau de la machine hôte. Il n'y a pas d'isolation logique au niveau du réseau, cela se traduit notamment par:
# Création d'un conteneur éphémère en mode interactif sur le réseau hote docker container run -it --rm --name test_host_net --net=host busybox:latest /bin/sh # Depuis l'interpréteur dans le conteneur on peut lister les interfaces # Les interfaces du conteneur sont identiques à celles de l'hote ip link show
Dans ce mode de fonctionnement le conteneur n'a pas besoin de règles de forwarding puisqu'il est directement lié aux interfaces de l'hote. Le port mapping de la commande --publish n'a donc aucun effet.
Les conteneurs créés sur le réseau hôte sont accessibles par les conteneurs utilisant le réseau Docker par défaut (docker0) et par les les conteneurs présent dans les réseaux de type pont créés par l'utilisateur.
Les ponts permettent à de multiples réseaux indépendants de coexister sur le même hôte physique. Seuls les conteneurs présents dans un même réseaux peuvent communiquer entre eux ou avec l’hôte. Si l’hôte accède à Internet, les conteneurs le pourront aussi. Cela permet d'isoler, de regrouper les conteneurs.
Parmi les réseaux en ponts on distingue:
Le réseau en pont par défaut nommé docker0 est créé automatiquement par Docker lors de l'installation.
# Depuis un interpréteur sur la machine hôte ip address show docker0
Par défaut le pont docker0 utilise un plan d'adressage 172.16.0.1/16. Ce paramétrage peut être modifié dans le fichier de configuration du daemon Docker /etc/default/docker.
Si aucune indication concernant le réseau n'est donnée sur la ligne de commande à la création du conteneur, c'est le pont par défaut qui est utilisé:
# Création d'un conteneur éphémère en mode interactif sans spécification du réseau docker container run -it --rm --name test_host_net busybox:latest # Depuis l'interpréteur dans le conteneur on peut lister les interfaces ip address show 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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 17: eth0@if18: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
Docker utilise iptables pour gérer le transmission des paquets (forwarding) avec le réseau en pont. Toutes les connexion sortantes semblent provenir d'une des adresses de l'hote (masquerading) et les connexions entrantes sont redirigée vers le bon conteneur via des règles de NAT.
Le pont par défaut docker0 supporte l'usage du mapping de ports via la commande --publish. L'option --link permet également de faire communiquer des conteneurs en partageant les variables d' environnement et en complétant le fichier de /etc/hosts (résolution de noms des conteneurs)
Docker permet à l'utilisateur de créer des réseaux personnalisés par pont (todo: voir également les réseau de type overlay). Ils réagissent de la même manière que le pont par défaut docker0. Les conteneurs présents dans le réseau peuvent communiquer directement entre eux tout en étant isolés des autres réseaux.
Au sein de ces réseaux, les conteneurs ont la capacité de se trouver mutuellement (se résoudre) via leur nom de conteneur (Docker intègre un service de DNS)
# Création d'un réseau par pont docker network create vnet_test # Création de 3 conteneurs éphémères dans le réseau vnet_test for i in {1..3}; do docker run -d --rm --name=node-${i} --net=vnet_test busybox:latest /bin/sh -c "sleep 300"; done # Lister les conteneurs existants docker container list --filter network=vnet_test --format 'table {{.ID}} {{.Names}}' CONTAINER ID NAMES 0339126c1815 node-3 95c20c4995a9 node-2 c4f61fa21a23 node-1 # Ouverture d'un shell dans le premier conteneur docker container exec -it node-1 /bin/sh # Depuis le conteneur node-1 # On peut contacter facilement les 2 autres conteneurs via leur nom de conteneur ping -c 1 node-2 PING node-2 (172.19.0.3): 56 data bytes 64 bytes from 172.19.0.3: seq=0 ttl=64 time=0.413 ms . . . ping -c 1 node-3 PING node-3 (172.19.0.4): 56 data bytes 64 bytes from 172.19.0.4: seq=0 ttl=64 time=0.247 ms . . .
La résolution fonctionne car le conteneur est paramétré pour utiliser comme résolveur le service DNS de Docker (127.0.0.11).
# Depuis le conteneur node-1 cat /etc/resolv.conf search mairie.local nameserver 127.0.0.11 options edns0 trust-ad ndots:0
Le service DNS de Docker maintient le mapping entre noms de conteneurs et adresses IP pour le réseau dans lequel le conteneur est connecté. Cette fonctionnalité facilite la découverte des nœuds du réseau.
Le tableau ci-dessous résume les différences entre le réseau par pont par défaut docker0 et les réseaux par pont créés par l'utilisateur.
Domaine | docker0 | Pont utilisateur |
---|---|---|
Déploiement du réseau | Créé par Docker lors de l'installation | Doit être créé par l'utilisateur. |
Association au conteneur | Le conteneur rejoint ce réseau par défaut | Doit utiliser explicitement l'argument --net et le nom du réseau pour joindre le conteneur au réseau. |
Liaison des conteneurs | L'usage de l'argument --link permet de relier plusieurs conteneurs | La liaison des conteneurs n'est pas supportée. |
Mapping des ports | supporté | supporté |
Resolveur de noms | non supporté ( la résolution fonctionne pour les conteneurs liés) | Les conteneurs dans le réseau résolvent les noms de ceux présents dans ce même réseau grace à la mise à jour du fichier /etc/hosts et au service DNS. |
Forwarding | utilise iptables | utilise iptables |
Il est également possible de créer un conteneur sans le connecter à un réseau via l'argument --net=none.