Gestion du réseau
Container Network Model
Docker s'appuie sur le Container Network Model (CNM) pour la configuration des interfaces réseaux des containers Linux.

Le CNM repose sur 3 composants :
- Sandbox : stack réseau d'un container
- Endpoint : interface réseau qui relie un container à un réseau
- Network : groupe de endpoints qui peuvent communiquer ensemble
Pour implémenter les drivers du CNM, Docker utilise différentes technologies :
- bridges linux
- namespaces réseau
- paire d'interfaces virtuelles (veth pairs)
- iptables
L'ensemble de ces éléments fournissent différentes fonctionnalités :
- Règles de gestion du trafic
- Segmentation réseau
- Service discovery
- Load balancing
- Routing mesh (Swarm, deprecated)
Cli
Comme pour les autres primitives Docker fournit un ensemble de fonctionnalités :
docker network --help
Usage: docker network COMMAND
Manage networks
Commands:
connect Connect a container to a network
create Create a network
disconnect Disconnect a container from a network
inspect Display detailed information on one or more networks
ls List networks
prune Remove all unused networks
rm Remove one or more networks
Run 'docker network COMMAND --help' for more information on a command.Drivers
La commande docker network create permet de créer un nouveau network en spécifiant le driver à utiliser :
docker network create --driver DRIVER [OPTIONS] NAMESuivant le driver utilisé, il sera possible d'utiliser certaines fonctionnalités
Par défaut plusieurs drivers sont disponibles :
- host
- none
- bridge
- overlay
- macvlan
Il est possible d'en installer d'autres, compatibles avec le CNM via des plugins comme par exemple Calico, Flannel.
Networks d'un hôte Docker
Par défaut Docker crée 3 networks
docker network ls
NETWORK ID NAME DRIVER SCOPE
f1c0b9915771 bridge bridge local
8b4b32a64a0f host host local
6ebccb73a16b none null local- Bridge
Créé sur la machine hôte et représenté par le bridge Linux docker0 il permet à l'ensemble des containers de pouvoir dialoguer. Par défaut, tous les containers démarrés sont visibles via ce bridge.
ip a show docker0
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:4d:d7:a8:ff brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft foreverIl est intéressant de noter qu'avec du bridge, la communication est limitée aux containers d'une même machine.

Pour pouvoir fonctionner le bridge, crée une paire d'interfaces virtuelles, l'une étant connectée au container et l'autre à la machine hôte.
Pour illustrer listons les interfaces bridges présentes sur la machine hôte
brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424dd7a8ff noDémarrons ensuite un container et regardons les interfaces réseaux
docker container run -ti alpine sh
ip a
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
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 foreverRegardons à nouveau les interfaces bridges
brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02424dd7a8ff no vethf8ac169Le container démarré est donc visible sur le bridge docker0.
Le mode bridge est cependant limité : il n'est pas possible de faire de la résolution de noms dans ce mode.
Pour illustrer démarrons un container basé sur l'image nginx
docker run -d --name=nginx
0a8514c66bf6946f55da967598777d3e7f4055f64f1dff55d5b7fb12cf446b72Récupérons l'ip du container
ocker inspect -f '{{.NetworkSettings.IPAddress}}' 0a8514
172.17.0.3Démarrons un nouveau container et essayons de pinger le container par son nom, puis son ip
docker run -it alpine sh
/ # ping -c3 nginx
ping: bad address 'nginx'
ping -c3 172.17.0.3Inspectons maintenant les détails du network bridge docker0
docker network ls
NETWORK ID NAME DRIVER SCOPE
f1c0b9915771 bridge bridge local
8b4b32a64a0f host host locanl
6ebccb73a16b none null localdocker inspect f1c0b9915771
[
{
"Name": "bridge",
"Id": "f1c0b99157713ab21716758a9405929ddee5ce46589090bdc5d118d7b436d43b",
"Created": "2021-11-27T09:24:28.563137709+01:00",
"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": {
"0a8514c66bf6946f55da967598777d3e7f4055f64f1dff55d5b7fb12cf446b72": {
"Name": "nginx",
"EndpointID": "f4a26177ab1ecf3d20724f7cc0f646c8b19464b324c93ecd59190cc4ae634ea6",
"MacAddress": "02:42:ac:11:00:03",
"IPv4Address": "172.17.0.3/16",
"IPv6Address": ""
},
"d557cc0af0adedc5c4aec2906f9042e582502e7827d17dd135394f7df6156ac1": {
"Name": "blissful_swartz",
"EndpointID": "4af5dbf4ca3f3acb47ec13765206c6d3a58987029fc9f59bf980b2522fbc0b95",
"MacAddress": "02:42:ac:11:00:02",
"IPv4Address": "172.17.0.2/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": "1500"
},
"Labels": {}
}
]On constate que les container précédents sont attachés au bridge par défaut étant donné qu'aucun network n'a été spécifié au démarrage des containers. En outre on illustre également ici la connectivité via des paires virtuelles, la machine hôte étant accessible via 172.17.0.1 là où par exemple le container nginx a pour ip 172.17.0.2.
- Host
Il permet d'accéder à la stack réseau de la machine hôte.
Démarrons un container
docker container run -it --network=host alpine shListons les networks depuis le container et depuis la machine hôte
ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp9s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether 04:92:26:d4:b1:d5 brd ff:ff:ff:ff:ff:ff
3: wlp6s0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000
link/ether be:d0:cd:94:cc:03 brd ff:ff:ff:ff:ff:ff
5: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:4d:d7:a8:ff brd ff:ff:ff:ff:ff:ff
15: virbr0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN qlen 1000
link/ether 52:54:00:74:28:1f brd ff:ff:ff:ff:ff:ffOn constate que les résultats sont identiques, le container a accès aux mêmes interfaces.
- None
Il donne à un container une interface locale et ne lui permet pas de dialoguer avec l'extérieur
Démarrons un container avec le driver none et listons les interfaces réseaux depuis celui-ci
docker container run -it --network none alpine sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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 foreverOn constate que seul le loopback est initialisé. Il peut être utile pour faire en sorte que le container démarré ne puisse pas être accédé depuis l'extérieur ; dans le cadre d'un container de debug par exemple.
Création d'un network bridge
Il est possible de créer un network de type bridge qui pourra être ensuite utilisé pour connecter des containers. Comme pour docker0 une paire d'interface bridge sera créée, dont une paire sera associée au container et dont l'autre sera connectée au namespace network root, c'est à dire à la machine hôte.
L'intérêt principal est de permettre la résolution DNS, ce qui n'est pas possible avec le docker0. C'est ce type de bridge qui sera créé par docker-compose lorsque que l'on définit les différents networks utilisables par les services. Pour aller plus loin la documentation du driver précise son fonctionnement.

Créons un nouveau nework de type bridge
docker network create --driver=bridge skynet
44568baae9fa5f2b8a27c3b03919ef1db97f0fcbcc45d3149b954f15089f990bListons les réseaux dispnoibles
docker network ls
NETWORK ID NAME DRIVER SCOPE
f1c0b9915771 bridge bridge local
8b4b32a64a0f host host local
6ebccb73a16b none null local
44568baae9fa skynet bridge locaLe réseau skynet est désormais disponible
Démarrons un container nginx sur ce network
docker run -d --name=nginx --network=skynet nginxOn peut désormais pinger ce container depuis un autre container
docker run -ti --name=alpine --network=skynet alpine sh
/ # ping -c3 nginx
PING nginx (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.094 ms
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.096 ms
64 bytes from 172.18.0.2: seq=2 ttl=64 time=0.095 ms
--- nginx ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.094/0.095/0.096 ms