web-dev-qa-db-fra.com

DNS ne fonctionne pas dans les conteneurs Docker lorsque Host utilise dnsmasq et que le serveur DNS de Google est pare-feu?

Le symptôme est le suivant: l'ordinateur hôte dispose d'un accès réseau approprié, mais les programmes s'exécutant dans des conteneurs ne peuvent pas résoudre les noms DNS (qui peuvent sembler "ne peuvent pas accéder au réseau" avant d'en savoir plus).

$ Sudo docker run -ti mmoy/ubuntu-netutils /bin/bash
root@082bd4ead733:/# ping www.example.com
... nothing happens (timeout) ... ^C
root@082bd4ead733:/# Host www.example.com
... nothing happens (timeout) ... ^C

(L'image docker mmoy/ubuntu-netutils est une image simple basée sur Ubuntu avec ping et Host incluse, pratique ici car le réseau est cassé et nous pouvons '' t apt install ces outils)

Le problème vient du fait que Docker a automatiquement configuré le DNS public de Google comme serveur DNS dans le conteneur:

root@082bd4ead733:/# cat /etc/resolv.conf 
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN

nameserver 8.8.8.8
nameserver 8.8.4.4

Cela ne fonctionne que dans de nombreuses configurations, mais évidemment pas lorsque l'hôte s'exécute sur un réseau où le DNS public de Google est filtré par certaines règles de pare-feu.

La raison pour laquelle cela s'est produit est:

  • Docker essaie d'abord de configurer les mêmes serveurs DNS sur l'hôte et dans le conteneur.
  • L'hôte exécute dnsmasq , un service de mise en cache DNS. dnsmasq agit comme un proxy pour les requêtes DNS, d'où le serveur DNS apparent dans le /etc/resolve.conf est nameserver 127.0.1.1, c'est-à-dire localhost.
  • Le dnsmasq de l'hôte écoute uniquement les demandes provenant de localhost et bloque les demandes provenant du conteneur Docker.
  • Depuis que vous utilisez 127.0.1.1 dans docker ne fonctionne pas, docker revient au DNS public de Google, qui ne fonctionne pas non plus.

Il peut y avoir plusieurs raisons pour lesquelles le DNS est rompu dans les conteneurs Docker. Cette question (et réponses) couvre le cas où:

  • dnsmasq est utilisé. Pour vérifier si tel est le cas:
  • Le DNS public de Google est filtré. Courir Host www.example.com 8.8.8.8. S'il échoue ou expire, vous êtes dans cette situation.

Quelles sont les solutions pour obtenir une configuration DNS correcte dans cette configuration?

18
Matthieu Moy

Une solution propre consiste à configurer docker + dnsmasq de sorte que les requêtes DNS du conteneur docker soient transmises au démon dnsmasq exécuté sur l'hôte.

Pour cela, vous devez configurer dnsmasq pour écouter l'interface réseau utilisée par docker , en ajoutant un fichier /etc/NetworkManager/dnsmasq.d/docker-bridge.conf:

$ cat /etc/NetworkManager/dnsmasq.d/docker-bridge.conf
listen-address=172.17.0.1

Redémarrez ensuite le gestionnaire de réseau pour que le fichier de configuration soit pris en compte:

Sudo service network-manager restart

Une fois cela fait, vous pouvez ajouter 172.17.0.1, c'est-à-dire l'adresse IP de l'hôte depuis Docker, vers la liste des serveurs DNS. Cela peut être fait soit en utilisant la ligne de commande:

$ Sudo docker run -ti --dns 172.17.0.1 mmoy/ubuntu-netutils bash
root@7805c7d153cc:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms

... ou via le fichier de configuration de docker /etc/docker/daemon.json (créez-le s'il n'existe pas):

$ cat /etc/docker/daemon.json                      
{
  "dns": [
    "172.17.0.1",
        "8.8.8.8",
        "8.8.4.4"
  ]
}

(cela reviendra au DNS public de Google si dnsmasq échoue)

Vous devez redémarrer docker pour que le fichier de configuration soit pris en compte:

Sudo service docker restart

Ensuite, vous pouvez utiliser docker comme d'habitude:

$ Sudo docker run -ti mmoy/ubuntu-netutils bash
root@344a983908cb:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.3 ms
19
Matthieu Moy

Étant donné que la découverte DNS automatique est coupable ici, vous pouvez remplacer le paramètre par défaut dans la configuration du docker.

Tout d'abord, obtenez l'IP du serveur DNS que dnsmasq utilise avec par exemple:

$ Sudo kill -USR1 `pidof dnsmasq`
$ Sudo tail /var/log/syslog 
[...]
Apr 24 13:20:19 Host dnsmasq[2537]: server xx.yy.zz.tt1#53: queries sent 0, retried or failed 0
Apr 24 13:20:19 Host dnsmasq[2537]: server xx.yy.zz.tt2#53: queries sent 0, retried or failed 0

Les adresses IP correspondent aux xx.yy.zz.tt espaces réservés ci-dessus.

Vous pouvez définir le DNS sur docker run temps avec le --dns option:

$ Sudo docker run --dns xx.yy.zz.tt1 --dns xx.yy.zz.tt2 -ti mmoy/ubuntu-netutils bash
root@6c5d08df5dfd:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.6 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=54 time=86.6 ms

Un avantage de cette solution est qu'aucun fichier de configuration n'est impliqué, donc aucun risque d'oublier la configuration et de rencontrer des problèmes plus tard à cause d'une configuration spécifique: vous obtenez cette configuration DNS si et seulement si vous tapez --dns option.

Vous pouvez également le définir de façon permanente dans le fichier de configuration de Docker, /etc/docker/daemon.json (créez-le, sur l'hôte, s'il n'existe pas):

$ cat /etc/docker/daemon.json
{
    "dns": ["xx.yy.zz.tt1", "xx.yy.zz.tt2"]
}

Vous devez redémarrer le démon docker pour prendre le daemon.json fichier en compte:

Sudo service docker restart

Ensuite, vous pouvez vérifier la configuration:

$ Sudo docker run -ti mmoy/ubuntu-netutils bash
root@56c74d3bd94b:/# cat /etc/resolv.conf 
nameserver xx.yy.zz.tt1
nameserver xx.yy.zz.tt2
root@56c74d3bd94b:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=54 time=86.5 ms

Notez que cela code en dur l'adresse IP DNS dans vos fichiers de configuration. Cela est fortement déconseillé si votre ordinateur est un ordinateur portable qui se connecte à différents réseaux et peut être problématique si votre fournisseur de services Internet modifie l'IP des serveurs DNS.

1
Matthieu Moy

Une solution brutale et dangereuse consiste à éviter la conteneurisation du réseau et à utiliser le même réseau sur l'hôte et sur le conteneur. Ce n'est pas sûr car cela donne accès à toutes les ressources réseau de l'hôte au conteneur, mais si vous n'avez pas besoin de cette isolation, cela peut être acceptable.

Pour ce faire, ajoutez simplement --network Host à la ligne de commande, par exemple.

$ Sudo docker run -ti --network Host mmoy/ubuntu-netutils /bin/bash
root@ubuntu1604:/# ping www.example.com
PING www.example.com (93.184.216.34) 56(84) bytes of data.
64 bytes from 93.184.216.34: icmp_seq=1 ttl=55 time=86.5 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=55 time=86.5 ms
1
Matthieu Moy

Une façon consiste à utiliser un réseau défini par l'utilisateur pour votre conteneur. Dans ce cas, le conteneur /etc/resolv.conf aura le serveur de noms 127.0.0.11 (alias le Docker serveur DNS intégré ), qui peut transmettre correctement les requêtes DNS à l'adresse de bouclage de l'hôte.

$ cat /etc/resolv.conf
nameserver 127.0.0.1
$ docker run --rm Alpine cat /etc/resolv.conf
nameserver 8.8.8.8
nameserver 8.8.4.4
$ docker network create demo
557079c79ddf6be7d6def935fa0c1c3c8290a0db4649c4679b84f6363e3dd9a0
$ docker run --rm --net demo Alpine cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0    

Si tu utilises docker-compose , il créera automatiquement un réseau personnalisé pour vos services (avec un format de fichier v2 + ). Notez, cependant, que tandis que docker-compose exécute des conteneurs dans un réseau défini par l'utilisateur, il les construit toujours dans le réseau par défaut . Pour utiliser un réseau personnalisé pour les builds, vous pouvez spécifier le paramètre network dans configuration de build (nécessite le format de fichier v3.4 + ).

1
Eugene Yarmash

Puisque dnsmasq est le problème, une option consiste à le désactiver sur l'hôte. Cela fonctionne, mais désactivera la mise en cache DNS pour toutes les applications exécutées sur l'hôte, c'est donc une très mauvaise idée si l'hôte est utilisé pour des applications autres que Docker.

Si vous êtes sûr de vouloir suivre cette voie, désinstallez dnsmasq, par exemple sur des systèmes basés sur Debian comme Ubuntu, exécutez apt remove dnsmasq.

Vous pouvez alors vérifier que /etc/resolv.conf dans le conteneur pointe vers le serveur DNS utilisé par l'hôte.

0
Matthieu Moy