Il existe de nombreuses façons dont les conteneurs Docker peuvent être confus au sujet des paramètres DNS (recherchez simplement SO ou sur Internet pour "Docker DNS" pour voir ce que je veux dire), et l'une des solutions de contournement courantes suggéré est de:
docker0
interface réseaudocker0
Adresse IP pour la résolution DNSCependant, essayer d'appliquer cette solution de contournement naïvement sur de nombreux systèmes Linux modernes vous enverra un rabbithole de complexité de gestion de réseau et de processus Linux, car systemd vous assure que dnsmasq
n'est pas en cours d'exécution, mais netstat
vous indique que c'est le cas et que la tentative de démarrage de dnsmasq
échoue avec la plainte que le port 53 est déjà utilisé.
Alors, comment donnez-vous de manière fiable à vos conteneurs un accès à un résolveur local exécuté sur l'hôte, même si le système en a déjà un par défaut?
Le problème ici est que de nombreux systèmes Linux modernes exécutent implicitement dnsmasq, donc ce que vous essayez maintenant de faire est de configurer une instance seconde spécifiquement pour Docker. Il y a en fait 3 paramètres nécessaires pour le faire correctement:
--interface=docker0
pour écouter sur l'interface réseau Docker par défaut--except-interface=lo
pour ignorer l'ajout implicite de l'interface de bouclage--bind-interfaces
pour désactiver une fonctionnalité dnsmasq où elle écoute toujours sur toutes les interfaces par défaut, même lorsque son seul trafic de traitement pour l'une d'entre ellesConfiguration d'une instance dnsmasq dédiée
Plutôt que de modifier les paramètres de l'instance dnsmasq à l'échelle du système par défaut, ces instructions montrent la configuration d'une instance dnsmasq dédiée avec systemd, sur un système qui définit déjà un service dnsmasq par défaut:
$ Sudo cp /usr/lib/systemd/system/dnsmasq.service /etc/systemd/system/dnsmasq-docker.service
$ sudoedit /etc/systemd/system/dnsmasq-docker.service
Tout d'abord, nous copions les paramètres de service par défaut dans un fichier de service dédié. Nous éditons ensuite ce fichier de service et recherchons la section de définition de service, qui devrait ressembler à ceci:
[Service]
ExecStart=/usr/sbin/dnsmasq -k
Nous modifions cette section pour définir nos options supplémentaires:
[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces
Le fichier entier est en fait assez court:
[Unit]
Description=DNS caching server.
After=network.target
After=docker.service
Wants=docker.service
[Service]
ExecStart=/usr/sbin/dnsmasq -k --interface=docker0 --except-interface=lo --bind-interfaces
[Install]
WantedBy=multi-user.target
Le [Unit]
la section indique à systemd d'attendre que la pile réseau et le démon docker principal soient disponibles pour démarrer ce service, tandis que [Install]
indique à quelle cible d'état du système ajouter le service lors de son activation.
Nous configurons ensuite notre nouveau service pour qu'il démarre au démarrage du système, et le démarrons également explicitement pour une utilisation immédiate:
$ Sudo systemctl enable dnsmasq-docker
$ Sudo systemctl start dnsmasq-docker
Comme dernière étape pour faire fonctionner le service, nous vérifions qu'il a réellement démarré comme prévu:
$ Sudo systemctl status dnsmasq-docker
Les deux lignes clés que nous recherchons dans cette sortie sont:
Loaded: loaded (/etc/systemd/system/dnsmasq-docker.service; enabled; vendor preset: disabled)
Active: active (running) since <date & time>
Sur la première ligne, notez l'état "activé", tandis que sur la seconde, l'état "actif (en cours)". Si le service n'a pas démarré correctement, alors les informations de diagnostic supplémentaires expliqueront, espérons-le, pourquoi (bien qu'il puisse parfois être malheureusement cryptique, d'où ce post).
Remarque: cette configuration peut ne pas démarrer dnsmasq-docker
au redémarrage du système avec une erreur sur le docker0
interface non définie. En attendant docker.service
semble être assez fiable pour éviter ce problème, si la résolution de noms à partir des conteneurs Docker ne fonctionne pas après un redémarrage du système, essayez d'exécuter:
$ Sudo systemctl start dnsmasq-docker
Configuration du pare-feu hôte
Pour pouvoir utiliser le résolveur à partir de conteneurs Docker locaux, nous devons également supprimer le pare-feu réseau entre l'hôte et les systèmes s'exécutant dans des conteneurs:
Sudo firewall-cmd --permanent --zone=trusted --change-interface=docker0
Sudo firewall-cmd --reload
(Ce serait une idée absolument terrible sur un hôte de conteneur de production, mais peut être un compromis risque/commodité utile sur un poste de travail de développeur)
Configuration de Docker à l'aide d'un fichier d'environnement systemd
Maintenant que notre résolveur local est en cours d'exécution, nous devons configurer Docker pour l'utiliser par défaut. Docker a besoin de l'adresse IP du docker0
interface plutôt que le nom de l'interface, nous utilisons donc ifconfig
pour récupérer cela:
$ ifconfig docker0 | grep inet
inet 172.17.0.1 netmask 255.255.0.0 broadcast 0.0.0.0
Donc, pour mon système, l'interface de l'hôte sur la valeur par défaut docker0
le pont est accessible en tant que 172.17.0.1
(Ajout de | cut -f 10 -d ' '
à cette commande devrait filtrer la sortie à l'adresse IP uniquement)
Puisque je suppose un Linux basé sur systemd avec un package Docker fourni par le système, nous interrogerons le fichier de service du package système pour savoir comment le service est démarré:
$ cat /usr/lib/systemd/system/docker.service
La première chose que nous recherchons est la commande exacte utilisée pour démarrer le démon, qui devrait ressembler à ceci:
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
La deuxième partie que nous recherchons est de savoir si le service est configuré ou non pour utiliser un fichier d'environnement, comme indiqué par une ou plusieurs lignes comme celle-ci:
EnvironmentFile=-/etc/sysconfig/docker
Lorsqu'un fichier d'environnement est utilisé (comme c'est le cas sur Fedora 23), la façon de modifier les paramètres du démon Docker consiste à modifier ce fichier et à mettre à jour la variable d'environnement appropriée:
$ sudoedit /etc/sysconfig/docker
L'entrée OPTIONS
existante sur Fedora 23 ressemble à ceci:
OPTIONS='--selinux-enabled --log-driver=journald'
Pour modifier les paramètres de résolution DNS par défaut, nous le modifions pour qu'il ressemble à ceci:
OPTIONS='--selinux-enabled --log-driver=journald --dns=172.17.0.1'
Et puis redémarrez le démon Docker:
$ Sudo systemctl restart docker
Avec cette modification mise en œuvre, les conteneurs Docker devraient désormais pouvoir accéder de manière fiable à tous les systèmes auxquels votre système hôte peut accéder (y compris via des tunnels VPN, ce qui était ma propre raison de devoir le comprendre)
Vous pouvez exécuter curl
dans un conteneur pour vérifier que la résolution de noms fonctionne correctement:
docker run -it centos curl google.com
Remplacer google.com
avec le nom d'hôte qui vous posait des problèmes (car vous n'auriez dû trouver cette réponse que si vous aviez un problème de résolution de nom lors de l'exécution d'un processus dans un conteneur Docker)
Configuration de Docker à l'aide d'un fichier de dépôt systemd
(Attention: étant donné que mon système utilise un fichier d'environnement, je n'ai pas pu tester l'approche basée sur un fichier de dépôt ci-dessous, mais cela devrait fonctionner - je l'ai inclus car la documentation Docker semble indiquer qu'ils préfèrent maintenant l'utilisation des fichiers drop-in systemd à l'utilisation des fichiers d'environnement)
Si le fichier de service système ne le fait pas utilise EnvironmentFile
, alors l'entrée entière ExecStart
peut être remplacée à l'aide d'un fichier de configuration de dépôt:
$ Sudo mkdir -p /etc/systemd/system/docker.service.d
$ sudoedit /etc/systemd/system/docker.service.d/daemon.conf
Nous demandons ensuite à Docker d'effacer l'entrée ExecStart existante et de la remplacer par notre nouvelle avec les paramètres supplémentaires:
[Service]
ExecStart=
ExecStart=/usr/bin/docker daemon \
$OPTIONS \
--dns 172.17.0.1 \
$DOCKER_STORAGE_OPTIONS \
$DOCKER_NETWORK_OPTIONS \
$INSECURE_REGISTRY
Nous demandons ensuite à systemd de charger cette modification de configuration et de redémarrer Docker:
$ Sudo systemctl daemon-reload
$ Sudo systemctl restart docker
Références:
Vous pouvez utiliser le résolveur DNS local de l'hôte (par exemple dnsmasq
) à partir de vos conteneurs Docker s'ils se trouvent sur un réseau défini par l'utilisateur . Dans ce cas, un 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 si docker-compose
exécute les 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 + ).