Comprendre les difficultés de la mise en réseau de conteneurs
Si vous avez déjà utilisé Docker ou des conteneurs, vous comprendrez la difficulté de les configurer pour communiquer entre eux.
Il y a tellement de problèmes et de cas extrêmes qui peuvent transformer la configuration de votre conteneur en cauchemar.
Dans cet article, je vais résumer pourquoi la mise en réseau de conteneurs est si délicate.
Pour comprendre la mise en réseau des conteneurs, nous devons comprendre les conteneurs.
J’ai déjà écrit en profondeur sur les conteneurs, mais si vous n’êtes pas familier avec eux, je vais les résumer ici.
En bref, les conteneurs sont des processus avec des étapes supplémentaires. Les conteneurs sont des processus isolés à l’aide de cgroups et d’espaces de noms Linux.
Mais pour des raisons de mise en réseau, nous nous concentrerons uniquement sur les espaces de noms.
Par défaut, chaque conteneur est créé dans son propre espace de noms réseau, avec sa propre pile réseau et ses interfaces distinctes de l’hôte. Chaque conteneur a même sa propre adresse IP.
L’adresse IP attribuée à l’interface réseau virtuelle du conteneur provient généralement d’une plage d’adresses IP privées, telle que 172.17.0.0/16
ou alors 10.0.0.0/8
. Cette adresse IP est locale au réseau privé de l’hôte et n’est accessible qu’au sein de l’hôte.
Cela signifie que chaque conteneur ne peut pas communiquer avec quoi que ce soit d’autre. Aucun autre conteneur, processus, et même pas l’hôte lui-même.
Pour permettre aux conteneurs sur le même hôte de communiquer avec d’autres conteneurs, Docker a plusieurs options de mise en réseau.
Mais le plus courant est le pont réseau.
Un pont réseau est un programme qui connecte plusieurs réseaux en un réseau plus vaste. Étant donné que chaque conteneur possède son propre espace de noms réseau, il est logique d’utiliser un pont pour communiquer.
Lorsque vous démarrez le démon Docker sur un serveur hôte, un pont réseau est créé avec le nom, docker0
.
Lorsque vous exécutez un conteneur, un périphérique Ethernet virtuel (veth) est créé sur le système hôte. Une extrémité du veth est connectée au conteneur et l’autre est connectée à un pont réseau sur l’hôte.
Si vous ne spécifiez pas de pont réseau, Docker utilisera le docker0
pont. Bien qu’il soit recommandé de créer votre propre réseau, ce qui est aussi simple que d’exécuter :
docker create network <network-name>
Le pont réseau agit comme un commutateur virtuel, transférant le trafic entre les conteneurs.
Les conteneurs qui font partie du même pont réseau peuvent communiquer entre eux sans problème en utilisant leurs adresses IP privées. Pas besoin de jouer avec les ports.
Le problème vient du fait de permettre aux conteneurs de communiquer avec Internet.
Alors que la mise en réseau de conteneurs comporte de nombreux éléments délicats, l’accès à Internet est le plus grand obstacle pour les novices et les nouveaux arrivants. Et cela a du sens, car de nombreuses pièces mobiles sont impliquées.
Voyons si nous ne pouvons pas le démystifier un peu.
L’avantage d’avoir chaque conteneur dans son propre espace de noms réseau est qu’ils n’ont pas de ports en conflit. Vous pouvez avoir tous vos conteneurs en écoute port 80
.
Le mauvais côté, cependant, est que puisque le réseau du conteneur n’est pas connecté au réseau de l’hôte, le conteneur ne peut pas être atteint par le réseau de l’hôte et vice versa.
Le moyen le plus simple pour un conteneur d’accéder à Internet est via le réseau de l’hôte. Donc, si vous voulez donner un accès Internet à votre conteneur, vous devez l’exposer à l’hôte.
Lorsque vous exposez un conteneur, vous dites à l’hôte de transférer le trafic vers le conteneur à l’aide d’un mappage de port.
Cette carte de port connecte le port du conteneur à un port public unique sur l’hôte.
Ainsi, vous pourriez avoir deux conteneurs d’applications différents à l’écoute port 80
mais chacun devrait être mappé à différents ports sur l’hôte (8080
et 8081
par exemple).
Prenons un exemple.
Disons que je voulais exposer un conteneur qui avait une adresse IP de 172.17.0.2
et écoutait sur le port 80
chez l’hôte 8080
Port.
La commande docker ressemblerait à ceci :
docker run my-container -p 8080:80
Cette commande exécute un conteneur et indique à l’hôte d’acheminer tout trafic réseau qui arrive sur le port 8080
au conteneur sur le port 80
.
Mais comment cela se passe-t-il sous le capot ?
Cela se fait généralement via iptables
règles qui transfèrent le trafic de l’hôte vers le conteneur.
Quelques exemples iptable
les règles peuvent ressembler à ceci lors de l’exposition d’un conteneur.
DNAT
Cette règle modifie l’adresse IP de destination d’un paquet réseau. Il est utilisé pour rediriger le trafic destiné à l’IP hôte vers l’IP du conteneur. Il redirigera tout le trafic entrant sur le port 8080
à l’adresse IP du conteneur (172.17.0.2
) sur bâbord 80
.
MASCARADE
Cette règle remplace l’adresse IP source d’un paquet par l’adresse IP de l’hôte. Il est utilisé lorsque le conteneur doit initier des connexions sortantes. Cela changera l’adresse IP source des paquets provenant de la plage d’adresses IP du conteneur (172.17.0.0/16
) à l’adresse IP de l’hôte, permettant au conteneur d’initier des connexions sortantes.
J’ACCEPTE
Cette règle permet au trafic entrant d’atteindre le conteneur sur un port spécifique. Il autorisera le trafic entrant vers l’adresse IP du conteneur (172.17.0.2
) sur bâbord 80
.
Comme vous pouvez l’imaginer, si vous avez des dizaines de conteneurs exécutés sur un seul hôte, la gestion de ces règles et ports peut devenir chaotique.