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:
/etc/resolve.conf
est nameserver 127.0.1.1
, c'est-à-dire localhost.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ù:
ps -e | grep dnsmasq
sur l'hôte. Si la sortie est vide, vous n'exécutez pas dnsmasq.nameserver 127.0.1.1
. S'il contient nameserver 127.0.0.53
, vous exécutez probablement systemd-resolved
au lieu de dnsmasq. Si c'est le cas, vous ne pourrez pas utiliser la solution pour faire passer les requêtes DNS à dnsmasq (celle qui utilise listen-address=172.17.0.1
). les hardcodes résolus par systemd le fait qu'il n'écoute que sur l'interface 'lo' donc il n'y a pas de moyen facile d'adapter cette solution . Les autres réponses ci-dessous fonctionneront avec la résolution de systemd.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?
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
É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.
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
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 + ).
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.