Le réseau bridge représente le réseau docker0 présent dans toutes les installations Docker.
Sauf indication contraire par le biais de l’option docker run --network=<NETWORK>, le démon Docker connecte les containers à ce réseau par défaut.
Note: Il existe quatre concepts importants concernant la mise en réseau bridge :
Docker0 Bridge
Network Namespace
Veth Pair
External Communication
Le bridge Docker0
Version Docker pour ce lab:
$ docker version
Client: Docker Engine - Community
Version: 24.0.1
API version: 1.43
Go version: go1.20.4
Git commit: 6802122 Built: Fri May 19 18:06:34 2023 OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 24.0.1
API version: 1.43 (minimum version 1.12) Go version: go1.20.4
Git commit: 463850e
Built: Fri May 19 18:06:34 2023 OS/Arch: linux/amd64
Experimental: false containerd:
Version: 1.6.21
GitCommit: 3dce8eb055cbb6872793272b4f20ed16117344f8
runc:
Version: 1.1.7
GitCommit: v1.1.7-0-g860f061
docker-init:
Version: 0.19.0
GitCommit: de40ad0
Via la commande docker network on obtient plus d’informations concernant le bridge docker0
$ docker network ls
NETWORK ID NAME DRIVER
32b93b141bae bridge bridge
c363d9a92877 host host
88077db743a8 none null
Vous pouvez également voir ce pont comme faisant partie de la pile réseau d’un hôte
à l’aide de la commande ifconfig/ip sur l’hôte.
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT qlen 1000 link/ether 06:95:4a:1f:08:7f brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN mode DEFAULT
link/ether 02:42:d6:23:e6:18 brd ff:ff:ff:ff:ff:ff
Comme il n’y a pas de container attaché à ce bridge docker0, il est down.
On peut aussi utilisaer la commande brctl pour obtenir plus d’informations sur le bridge docker0
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242d623e618 no veth6a5ae6f
Note: Si vous ne trouvez pas la commande brctl, vous devrez l’installer. Pour les distribution RedHat Like,
utilisez sudo yum install bridge-utils. Pour les distribution Debian Like, il faut utiliser apt-get install bridge-utils
Veth Pair
Nous allons créer un container centos7:
$ docker run -d --name test1 centos:7 /bin/bash -c "while true; do sleep 3600; done"$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4fea95f2e979 centos:7 "/bin/bash -c 'while "6 minutes ago Up 6 minutes test1
Nous pouvons vérifier l’interface IP sur l’hôte docker.
$ ip li
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT qlen 1000 link/ether 06:95:4a:1f:08:7f brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT
link/ether 02:42:d6:23:e6:18 brd ff:ff:ff:ff:ff:ff
15: vethae2abb8@if14: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT
link/ether e6:97:43:5c:33:a6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
Le bridge docker0 est up, et il y a une paire veth créée, une est sur le localhost, et l’autre dans le nampespace du container.
ESpace de nom réseau
Si on ajoute un nouvel espace de nom réseau à partie de la ligne de commande
$ sudo ip netns add demo
$ ip netns list
demo
$ ls /var/run/netns
demo
$ sudo ip netns exec demo ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
Mais à partir de la commande ip netns list, nous ne pouvons pas obtenir l’espace de noms réseau du container.
Docker a supprimé tous les informations des espaces de noms réseau des container de /var/run/netns.
On peux récupérer tous les espaces de noms réseau à partir de /var/run/docker/netns.
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4fea95f2e979 centos:7 "/bin/bash -c 'while "2 hours ago Up About an hour test1
$ sudo ls -l /var/run/docker/netns
total 0-rw-r--r--. 1 root root 0 Nov 28 05:51 572d8e7abcb2
Comment récupérer toutes les informations(comme veth) concernant l’espace de nom réseau du container ?
Nous devons récupérer dans un premier temps le pid du process du container, et récupérer tous les espaces de noms de ce container.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4fea95f2e979 centos:7 "/bin/bash -c 'while "2 hours ago Up 2 hours test1
$ docker inspect --format '{{.State.Pid}}' 4f
3090$ sudo ls -l /proc/3090/ns
total 0lrwxrwxrwx. 1 root root 0 Nov 28 05:52 ipc -> ipc:[4026532156]lrwxrwxrwx. 1 root root 0 Nov 28 05:52 mnt -> mnt:[4026532154]lrwxrwxrwx. 1 root root 0 Nov 28 05:51 net -> net:[4026532159]lrwxrwxrwx. 1 root root 0 Nov 28 05:52 pid -> pid:[4026532157]lrwxrwxrwx. 1 root root 0 Nov 28 08:02 user -> user:[4026531837]lrwxrwxrwx. 1 root root 0 Nov 28 05:52 uts -> uts:[4026532155]
Ensuite on restaure l’espace de nom réseau:
$ sudo ln -s /proc/3090/ns/net /var/run/netns/3090
$ ip netns list
3090demo
$ sudo ip netns exec3090 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
Ensuite c’est bon, il faut supprimer /var/run/netns/3090.
Communication Externe
Tous les containers connectés au bridge docker0 peuvent communiqués avec le réseau externe ou d’autres containers connectés au même bridge.
Démarrons deux containers:
$ docker run -d --name test2 centos:7 /bin/bash -c "while true; do sleep 3600; done"8975cb01d142271d463ec8dac43ea7586f509735d4648203319d28d46365af2f
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8975cb01d142 centos:7 "/bin/bash -c 'while "4 seconds ago Up 4 seconds test2
4fea95f2e979 centos:7 "/bin/bash -c 'while "27 hours ago Up 26 hours test1
Et à partir du bridge docker0, on peux voire deux inrterfaces connectées.
$ brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242d623e618 no veth6a5ae6f
vethc16e6c8
$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9001 qdisc pfifo_fast state UP mode DEFAULT qlen 1000 link/ether 06:95:4a:1f:08:7f brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT
link/ether 02:42:d6:23:e6:18 brd ff:ff:ff:ff:ff:ff
27: veth6a5ae6f@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT
link/ether 02:7d:eb:4e:85:99 brd ff:ff:ff:ff:ff:ff link-netnsid 031: vethc16e6c8@if30: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT
link/ether d2:9f:2e:ca:22:a5 brd ff:ff:ff:ff:ff:ff link-netnsid 1
Les deux containers peuvent communiquer
$ docker inspect --format '{{.NetworkSettings.IPAddress}}' test1
172.17.0.2
$ docker inspect --format '{{.NetworkSettings.IPAddress}}' test2
172.17.0.3
$ docker exec test1 bash -c 'ping 172.17.0.3'PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1ttl=64time=0.051 ms
64 bytes from 172.17.0.3: icmp_seq=2ttl=64time=0.058 ms
64 bytes from 172.17.0.3: icmp_seq=3ttl=64time=0.053 ms
^C
Le réseau de base doit être comme ci-dessous:
CNM
Pour comprendre comment le conteneur obtient son adresse IP, vous devez comprendre
qu’est-ce que CNM (Container Network Model)1.
Libnetwork implémente Container Network Model (CNM) qui formalise les
étapes nécessaires pour fournir une mise en réseau pour les conteneurs tout en fournissant un
abstraction pouvant être utilisée pour prendre en charge plusieurs pilotes réseau.
Au cours du cycle de vie du réseau et des terminaux, le modèle CNM contrôle
Attribution d’adresse IP pour les interfaces réseau et terminal via l’IPAM
conducteur(s)2.
Lors de la création du pont docker0, libnetwork fera une requête vers le pilote IPAM,
quelque chose comme une passerelle réseau, un pool d’adresses. Lors de la création
un conteneur, dans le bac à sable du réseau, et un point de terminaison a été créé,
libnetwork demandera une adresse IPv4 au pool IPv4 et l’attribuera
à l’adresse IPv4 de l’interface du point de terminaison.
NAT
Les containers avec leur réseau en mode bridge peuvent accéder au réseau externe au travers du NAT qui est configuré via iptables.
Dans le container:
# ping www.google.comPING www.google.com (172.217.27.100) 56(84) bytes of data.
64 bytes from sin11s04-in-f4.1e100.net (172.217.27.100): icmp_seq=1ttl=61time=99.0 ms
64 bytes from sin11s04-in-f4.1e100.net (172.217.27.100): icmp_seq=2ttl=61time=108 ms
64 bytes from sin11s04-in-f4.1e100.net (172.217.27.100): icmp_seq=3ttl=61time=110 ms
^C
--- www.google.com ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 99.073/106.064/110.400/4.990 ms
A partir du server docker, on peut voir:
$ sudo iptables --list -t nat
Chain PREROUTING (policy ACCEPT)target prot opt source destination
DOCKER all -- anywhere anywhere ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)target prot opt source destination
Chain OUTPUT (policy ACCEPT)target prot opt source destination
DOCKER all -- anywhere !loopback/8 ADDRTYPE match dst-type LOCAL
Chain POSTROUTING (policy ACCEPT)target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 anywhere
Chain DOCKER (2 references)target prot opt source destination
RETURN all -- anywhere anywhere
Pour le NAT au travers d’iptables, on peux se référer34