Résoudre les IPs de vos conteneurs docker avec dnsdock et systemd-resolved
Quoi de plus pénible avec docker que de trouver l’adresse de son conteneur ou de mapper
le port sur le host pour joindre votre service. Si vous jouer régulièrement avec
les conteneurs sur votre machine ça devient vite indispensable d’utiliser
un DNS local pour faire le taff. Avec dnsdock
vous allez pouvoir facilement joindre
vos services conteneurisés.
Joindre son conteneur sans DNS
Mapper le port sur le host
Quand on débute avec les conteneurs les tutoriels vous suggèrent par simplicité de mapper le port de votre conteneur. Le but étant d’accéder au service depuis l’IP local de votre machine via une URL de ce type http://127.0.0.1:8000. Ce qui donne la commande docker suivante:
~ docker run -it --rm -p 8000:80 nginx
Dans cette exemple docker a créé une règle pour rediriger le trafic arrivant sur le port 8000 de votre machine vers l’IP du conteneur sur le port 80. Si vous suivez cette exemple jusqu’au bout vous pouvez admirer la page par défaut de nginx avec l’URL http://localhost:8000.
Effectivement ça fonctionne, mais ça peux rapidement poser problème. Ce n’est pas évolutif. Et vous ne pouvez pas lancer n conteneurs nginx avec la même commande il faut assigner un autre port pour le host 8001, 8002… Si vous bossez sur plusieurs projets avec du nginx comme serveur http ça va vite être la galère pour retrouver la bonne URL.
Obtenir l’adresse du conteneur
Pour éviter d’utiliser le mapping, vous pouvez simplement joindre votre service
via l’IP de votre conteneur. Pour ça il faut utiliser la commande docker inspect
et retrouver l’adresse dans tout le flux json
de sortie. Avec la commande docker
vous pouvez facilement filtrer la sortie pour obtenir uniquement l’IP.
~ docker run -it --rm --name http nginx
~ docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' http
172.18.0.3
Ici, il est donc possible de joindre le service en question via son IP 172.18.0.3
et d’afficher
la page via l’URL http://172.18.0.3 car notre service nginx écoute sur le port 80 par défaut.
La méthode est différente, il n’est plus question de polluer le host avec un mapping du port certes mais il faut quand même aller à la recherche de l’IP! Et si l’utilisateur décide de redémarrer le conteneur, celle-ci a de forte chance de changer.
Joindre son conteneur avec dnsdock
Pour résoudre les problématiques vu ci-dessus, il y a le projet dnsdock.
Le projet n’est pas nouveau, il a plus de 6 ans. dnsdock
est un serveur DNS qui utilise
la socket docker pour découvrir les conteneurs disponible. La difficulté première
est de l’intégrer correctement dans votre environnement, ça tombe bien c’est le sujet de cet article.
Par défaut tous vos conteneurs seront joignable avec le domaine de premier niveau .docker
.
Lancer dnsdock
Avant de lancer dnsdock
, il faut identifier votre interface réseau docker. Généralement nommé docker0
.
~ DOCKER_IP=$(ip -f inet addr s docker0 | grep -Po 'inet \K[\d.]+')
~ echo $DOCKER_IP
172.18.0.1
Dans l’étape suivante, exécuter le service dnsdock
en mappant le port 53
sur l’interface docker. Puis ajouter la règle de redémarrage always
pour que le conteneur
soit relancé automatiquement au reboot de la machine.
~ docker run -d --restart always -v /var/run/docker.sock:/var/run/docker.sock --name dnsdock -p $DOCKER_IP:53:53/udp aacebedo/dnsdock:latest-amd64
Pour vérifier, que ça marche correctement, vous pouvez obtenir l’IP du conteneur
dnsdock
avec l’outil dig
. Spécifier l’adresse du serveur DNS soit l’interface docker0.
~ dig A @$DOCKER_IP dnsdock.docker +short
172.18.0.2
Par contre, il n’est pas encore possible de joindre le service. Pour cela il faut modifier
le DNS local de votre système. Pour la majorité cela devrait être systemd-resolved
, par défaut
depuis Ubuntu 16.10 et Fedora 33.
Configuration de systemd-resolved
Premièrement, utiliser la commander ss
pour identifier votre DNS local.
Le résultat de la commande ci-dessous liste les service qui écoutent sur le port 53. Sur ma machine,
je retrouve bien mon service dnsdock
à travers le proxy docker et mon résolveur DNS local
systemd-resolved
.
~ sudo ss -pua '( sport = :domain )'
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
UNCONN 0 0 172.18.0.1:domain 0.0.0.0:* users:(("docker-proxy",pid=4010945,fd=4))
UNCONN 0 0 127.0.0.53%lo:domain 0.0.0.0:* users:(("systemd-resolve",pid=902546,fd=16))
Maintenant nous allons ajouter un fichier de configuration pour prendre en compte les domaines *.docker
.
Editer /etc/systemd/resolved.conf.d/docker.conf
avec le contenu suivant, où l’adresse 172.18.0.1
correspond à DOCKER_IP
(la variable qui stock l’IP de mon interface docker).
[Resolve]
DNS=172.18.0.1:53#docker
Domains=docker
Après un redémarrage du service vous pouvez à présent joindre le service dnsdock
.
Avec resolvectl
vous pouvez résoudre l’IP et vérifier que l’interface réseau docker
est bien utilisée. Et pour finir vous pouvez vérifier que le service est bien joignable avec
l’outil ping
par exemple.
~ sudo systemctl restart systemd-resolved
~ resolvectl query dnsdock.docker
dnsdock.docker: 172.18.0.2 -- link: docker0
-- Information acquired via protocol DNS in 3.6ms.
-- Data is authenticated:
~ ping -c1 dnsdock.docker
PING dnsdock.docker (172.18.0.2) 56(84) bytes of data.
64 bytes from 172.18.0.2 (172.18.0.2): icmp_seq=1 ttl=64 time=0.101 ms
Voila nous y sommes ! Plus besoin de rechercher manuellement l’adresse de votre
conteneur. Par défaut vous pouvez le joindre avec un nom de domaine. Celui-ci
correspond au nom de votre image docker. Pour les noms plus complexe sous forme
de path, le nom de domaine utilise la fin du path. Dans notre exemple le path complet
de l’image docker de notre service est aacebedo/dnsdock
. Celui-ci est joignable
avec le domaine dnsdock.docker
.
Exemple pour personnaliser l’enregistrement DNS
Pour personnaliser les enregistrements DNS de vos conteneurs vous pouvez
utiliser les labels docker. Il y a beaucoup de possibilités en plus de celle
proposés par défaut je vous invite à suivre la doc officiel. Ci-dessous un exemple pour ajouter un enregistrement
avec le label com.dnsdock.alias
en plus de ceux définit par défaut.
~ docker run -it --rm --name ui -l com.dnsdock.alias=ui-nginx.docker nginx
Une fois lancé, charger la page depuis votre navigateur avec l’une des URL suivantes:
- http://nginx.docker http://
<nom de l'image>
.docker - http://ui.nginx.docker http://
<nom du conteneur>.<nom de l'image>
.docker - http://ui-nginx.docker http://
<alias via le label docker>
Conclusion
Le principal avantage d’avoir cette configuration sur votre machine est de pouvoir déployer facilement en local des applications webs. Depuis votre navigateur vous allez pouvoir atteindre vos services back-end simplement et ça ne vas pas rentrer en conflit avec d’autres applications.