Le VPN est actif, le navigateur atteint les sites internes, et le conteneur ne parvient toujours pas à résoudre les mêmes noms. Une installation de paquet meurt sur une erreur de résolution de nom comme EAI_AGAIN, ou une application ne trouve pas un hôte de base de données que la machine hôte résout sans la moindre plainte. Le conteneur n’utilise pas le résolveur que le VPN a installé. Docker a copié la configuration du résolveur de l’hôte lors de la création du conteneur, et rien ne l’a recopiée ensuite.

Deux vues du résolveur sur une même machine

Sous Linux, Docker donne à chaque conteneur une copie de la configuration du résolveur de l’hôte au moment de la création, filtre les adresses de loopback et exécute un serveur DNS intégré à 127.0.0.11 qui transmet les requêtes vers l’extérieur. Un client VPN qui réécrit /etc/resolv.conf après le démarrage du conteneur ne change rien à l’intérieur de celui-ci. Redémarrer le conteneur n’aide que si le résolveur de l’hôte est justement correct à ce moment-là.

Docker Desktop sous macOS ou Windows ajoute une couche, car le démon vit dans une machine virtuelle. Le résolveur VPN de l’hôte peut n’être jamais visible pour cette VM, si bien qu’un redémarrage ne change absolument rien. Comparez les deux vues avant de choisir une correction : docker exec mycontainer cat /etc/resolv.conf à côté de la liste des résolveurs de l’hôte.

Un conteneur qui liste un résolveur public alors que l’hôte en liste un interne résoudra les noms publics et échouera sur les internes. Cette séparation est la signature de ce problème.

Option A : passer le résolveur du tunnel par conteneur

Docker accepte des réglages DNS par conteneur, ce qui est le plus petit changement qui fonctionne. Lisez d’abord les adresses du résolveur du VPN : scutil --dns sous macOS, resolvectl status ou la sortie d’état du client lui-même sous Linux. Démarrez ensuite le conteneur avec elles, par exemple docker run --dns 192.168.2.1 --dns 192.168.123.1 myimage. Dans Compose, le même réglage est une liste sous le service, où il vit dans le contrôle de version plutôt que dans l’historique de shell de quelqu’un.

Un tableau dns dans /etc/docker/daemon.json s’applique à chaque nouveau conteneur, ce qui semble plus propre et ne l’est pas. Il s’applique aussi lorsque le tunnel est coupé, et un résolveur accessible uniquement par le VPN casse alors les téléchargements d’images ordinaires. Les réglages par conteneur sont plus faciles à justifier et plus faciles à annuler.

Option B : laisser le conteneur partager le réseau de l’hôte

Le réseau de l’hôte contourne entièrement la copie, car le conteneur utilise le résolveur de l’hôte et le tunnel de l’hôte. Il supprime aussi l’isolation réseau que vous vouliez probablement, et il ne se comporte pas de la même façon sous Docker Desktop. Sous Linux, c’est le choix pragmatique pour un outil ponctuel qui doit résoudre des noms internes.

Pour les compilations, aucune des deux options ne s’applique, car les étapes de compilation n’héritent pas des indicateurs d’exécution. Compilez avec le réseau de l’hôte là où la plateforme le permet, ou gardez l’installation des dépendances dans une étape qui n’a pas besoin du tunnel.

Ce qu’aucune des deux options ne corrige

Une adresse DNS est inutile si le conteneur n’a pas de route vers elle. Le résolveur du VPN se trouve généralement dans l’espace d’adressage du tunnel, donc le conteneur a besoin d’un chemin vers ce préfixe. Le pont par défaut de Docker achemine normalement vers l’extérieur via l’hôte, ce qui suffit lorsque l’hôte possède la route du tunnel et que le transfert est activé. Des réseaux pont personnalisés avec leurs propres plages d’adresses peuvent entrer en collision avec le sous-réseau du VPN, et les requêtes partent alors tout à fait ailleurs.

Vérifiez le sous-réseau du réseau Docker par rapport au sous-réseau du VPN avant de déboguer le résolveur lui-même. Un chevauchement produit une panne qui ressemble exactement à un serveur DNS cassé.

Vérifier à l’intérieur du conteneur

Testez avec getent hosts db.internal à l’intérieur du conteneur plutôt qu’avec un navigateur ou un environnement d’exécution de langage, car ceux-ci appliquent leur propre politique DNS et leur propre cache. Si getent résout le nom et que l’application échoue toujours, le résolveur est désormais correct et le problème restant se situe au niveau de l’application. S’il ne le résout pas, l’étape DNS n’est pas terminée.

Recréez le conteneur après avoir modifié ses réglages DNS. Modifier /etc/resolv.conf à l’intérieur d’un conteneur en cours d’exécution disparaît avec lui et masque le problème de configuration exactement le temps qu’il faut à quelqu’un pour le redémarrer.

Articles similaires