Arrivé avec la version 1.9 en octobre 2015, les networks de Docker ont apporté une meilleur gestion de la configuration réseaux et remplace aisément l’ancienne fonctionnalités de linking de Docker.
La gestion des networks a été égalementajoutée à la version 2 de docker-compose, ce qui aurait dû en accélérer l’adoption. Pourtant, on trouve beaucoup d’exemples récents n’utilisant pas encore les networks, et trop de personnes ne savent pas utiliser pleinement.
Je vous propose donc un petit tour d’horizon des fonctionnalités apportées par Docker Network
Un seul network bridge et la fonction link
Par défaut, il existe un network appelé bridge (l’interface docker0 quand vous faites un ifconfig). Ce network est créé en même temps que l’installation de docker. Il est toujours utilisé par défaut si vous ne spécifiez de réseaux au lancement d’un container (–network=custom_network).
Dans ce réseau bridge créé par défaut, tous les containers peuvent communiquer entre eux, et donc se faire pirater par le premier container venu.
Si vous voulez interdire ce fonctionnement, il faut mettre l’option icc à false dans le fichier de configuration de docker (voir l’article Docker Sécurité : 10 bonnes pratiques chapitre Interdire les communications entre les containers)
Historiquement, la fonction link propose 4 fonctionnalités
- Résolution de nom entre les containers
- Créer des alias
- Ouvrir les connections entre certains container (quand l’isolation était activé, via –icc=false)
- Injecter les variables d’environnement d’un container à un autre
Pour assurer la retro-compatibilité avec les anciennes version, le fonctionnement de link reste inchangé quand on utilise encore le réseau bridge crée par défaut. Docker appelle ça le legacy Link
Le Legacy Link avait quelques défauts, il ne supportait pas les restarts des containers par exemple. Les links étaient simplement ajouté dans le fichier /etc/hosts au démarrage du container et n’était pas remis à jour pour prendre en compte d’eventuel changement d’ip.
J’ai réalisé une image w3blogfr/docker-topology-network qui liste toutes les adresses ip accessible depuis le container lancé. Je vous invite à la lancer chez vous si vous avez des containers lancés, elle permet de se rendre compte que par défaut, tous containers peuvent se voir.
docker run --rm --name docker-topology-network w3blogfr/docker-topology-network 172.17.0.1 172.17.0.2 172.17.0.3 f11c0c7d6b99 (172.17.0.4)
Docker networks
La principale fonctionnalités de Docker network est déjà de simplement pouvoir créer plusieurs networks. Cela vous permet de regrouper plusieurs containers entre eux, les groupes ainsi créés sont isolés les uns des autres, ce qui limite les risques et les conflits. A noter qu’un container peux appartenir à zéro ou plusieurs réseaux.
Si vous utiliser la version 2 de docker-compose, docker-compose créé par défaut un nouveau réseau pour regrouper et isoler tous les containers lancés par le même fichier yml
docker-compose up Creating network "w3blogdemo_default" with the default driver
Docker Compose utilise le nom du repertoire pour définir le nom de son réseau. Des containers lancés par docker-compose dans plusieurs répertoire différents seront donc incapable de communiquer entre eux.
Vous pouvez voir la liste des networks grâce à la commande
docker network ls NETWORK ID NAME DRIVER SCOPE 752abe418caa bridge bridge local 0044b07d8d26 host host local c73c9f7727f2 none null local 869d12ce609c w3blogdemo_default bridge local
Vous les verrez également apparaître avec la commande ifconfig, ce sont toutes les interfaces commençant par ‘br-‘
Attention, le legacy link ne s’applique qu’au network bridge créé par défaut, celui avec pour nom « bridge ». Les autres réseaux créés par la suite utilisent toutes les fonctionnalités de docker network et le nouveau système de link (même si le driver s’appelle également bridge)
Pour les réseaux créés manuellement par l’utilisateur ou par docker-compose,
- Les noms sont résolus en utilisant un DNS propre à chaque réseau, le fichier /etc/hosts n’est plus utilisé)
- la fonction link ne sert qu’à créer des alias et ne gère plus la communication entre les containers
- Les variables d’environnement ne sont plus injectés entre les containers (même si vous utilisez link)
Si je relance mon image w3blogfr/docker-topology-network avec l’option –network
docker run --rm --network=w3blogdemo_default --name docker-topology-network w3blogfr/docker-topology-network 172.22.0.1 nginx.w3blogdemo_default (172.22.0.2) w3blogdemo_tomcat2_1.w3blogdemo_default (172.22.0.3) w3blogdemo_tomcat_1.w3blogdemo_default (172.22.0.4) 3a05ba2e0ecf (172.22.0.5)
Seul les containers liés à mon réseau apparaissent, on voit d’ailleurs que docker utilise une autre tranche d’adresse IP en 172.22.
Mon utilitaire a également pu résoudre une partie des noms des containers grâce au DNS embarqué par Docker Network
Docker Compose et Network
Pour utiliser docker network avec docker-compose, il ne suffit pas d’installer la version 2. il faut ajouter une ligne dans vos fichiers yml pour forcer l’utilisation de la version 2.
version: "2" services: nginx: image: nginx:1.11 ports: - "80:80" networks: - front-network - back-network tomcat: image: tomcat:8.0 networks: - back-network tomcat2: image: tomcat:8.0 networks: - back-network networks: front-network: driver: bridge back-network: driver: bridge
On peux définir directement les réseaux depuis docker-compose, et sélectionner pour chaque service le ou les réseaux souhaités. Si ce n’est pas nécessaire, un container peux n’avoir aucun réseau, il sera alors isolé de tous les réseaux existants.
Cela apporte une meilleur isolation des containers, mais permet également une gestion avancée des connexions réseaux. Dans l’exemple, nous avons créé 2 réseaux: front et back. Nginx est utilisé comme frontal et il doit communiquer avec le backend, il doit donc appartenir aux 2 réseaux.
Quand l’expert réseau intervient
Les réseaux étant bien identifié fonctionnellement par le développeur, un expert réseaux pourra facilement passer derrière lui pour sécuriser et optimiser les connexions grâce à son outil préféré : iptables
Il va alors s’appuyer sur les interfaces réseaux créé par docker (visible avec ifconfig) pour interdire certains accès et/ou rediriger le trafic sur la bonne interface réseaux physique ou virtuel.
- Dans le cas d’un serveur physique, on pourrait envisager que les accès via l’ip public du serveur ne puisse accéder qu’au réseau front-network et donc à nginx. Le réseau back-network serait de son côté rattaché au réseau interne de l’entreprise via une autre réseau physique.
- Dans le cas d’un déploiement sur une solution virtualisée (vSphere par exemple), le réseau back-network pourrait communiquer avec les autres serveurs virtualisés directement par le réseau interne de vSphere, ce qui permet d’optimiser les performances.
Docker Network apporte une solution qui peux convenir aussi bien aux développeurs qu’aux administrateurs systèmes et réseaux.
Dans cet article, nous avons parlé principalement du driver bridge, il existe également un autre driver appelé overlay qui permet de gérer des réseaux Docker multi-host via différentes solutions : Docker Swarm, Kubernetes, Fleet. J’essayerais de vous en parler dans un prochain article, mais le sujet est très vaste.
Pour aller plus loin, je vous conseille la documentation de Docker : Understand Docker container networks
Bon article qui met en avant une fonctionnalité encore peu connu, merci !
J’irai même encore un peu plus loin en expliquant comment gérer les plages d’IP. C’est souvent ce que cherche les développeurs pour assigner des IP fixes à leurs containers :
Exemple :