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:

ui-nginx.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.

Sources 123