web-dev-qa-db-fra.com

Docker 1.10 accède à un conteneur par son nom d'hôte depuis une machine hôte

J'ai la version 1.10 de Docker avec le service DNS intégré.

J'ai créé deux conteneurs de service dans mon fichier docker-compose. Ils sont accessibles les uns aux autres par nom d'hôte et par IP, mais quand je voudrais atteindre l'un d'eux depuis la machine hôte, cela ne fonctionne pas, cela ne fonctionne qu'avec IP mais pas avec nom d'hôte.

Alors, est-il possible d'accéder à un conteneur Docker depuis la machine hôte par son nom d'hôte dans le Docker 1.10, s'il vous plaît?

Mise à jour:

docker-compose.yml

version: '2'
services:
    service_a:
        image: nginx
        container_name: docker_a
        ports:
           - 8080:80
    service_b:
        image: nginx
        container_name: docker_b
        ports:
            - 8081:80

puis je le démarre par commande: docker-compose up --force-recreate

quand je cours:

  • docker exec -i -t docker_a ping -c4 docker_b - Ça marche
  • docker exec -i -t docker_b ping -c4 docker_a - Ça marche
  • ping 172.19.0.2 - Ça marche (172.19.0.2 est docker_b'siroter)
  • ping docker_a - échoue

Le résultat du docker network inspect test_default est

[
    {
        "Name": "test_default",
        "Id":   "f6436ef4a2cd4c09ffdee82b0d0b47f96dd5aee3e1bde068376dd26f81e79712",
        "Scope": "local",
        "Driver": "bridge",
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1/16"
                }
            ]
        },
        "Containers": {
             "a9f13f023761123115fcb2b454d3fd21666b8e1e0637f134026c44a7a84f1b0b": {
                "Name": "docker_a",
                "EndpointID":     "a5c8e08feda96d0de8f7c6203f2707dd3f9f6c3a64666126055b16a3908fafed",
                "MacAddress": "02:42:ac:13:00:03",
                "IPv4Address": "172.19.0.3/16",
                "IPv6Address": ""
            },
                "c6532af99f691659b452c1cbf1693731a75cdfab9ea50428d9c99dd09c3e9a40": {
                "Name": "docker_b",
                "EndpointID":     "28a1877a0fdbaeb8d33a290e5a5768edc737d069d23ef9bbcc1d64cfe5fbe312",
                "MacAddress": "02:42:ac:13:00:02",
                "IPv4Address": "172.19.0.2/16",
                "IPv6Address": ""
            }
        },
        "Options": {}
    }
]
31
Adam Bernau

Voici ce que je fais.

J'ai écrit un script Python appelé dnsthing , qui écoute l'API des événements Docker pour le démarrage ou l'arrêt des conteneurs. Il gère un fichier de style hosts avec les noms et adresses des conteneurs. Les conteneurs sont nommés <container_name>.<network>.docker, par exemple si je lance ceci:

docker run --rm --name mysql -e MYSQL_ROOT_PASSWORD=secret  mysql

J'ai compris:

172.17.0.2 mysql.bridge.docker

J'exécute ensuite un processus dnsmasq pointant vers ce fichier hosts. Plus précisément, j'exécute une instance dnsmasq en utilisant la configuration suivante:

listen-address=172.31.255.253
bind-interfaces
addn-hosts=/run/dnsmasq/docker.hosts
local=/docker/
no-hosts
no-resolv

Et j'exécute le script dnsthing comme ceci:

dnsthing -c "systemctl restart dnsmasq_docker" \
  -H /run/dnsmasq/docker.hosts --verbose

Alors:

  • dnsthing mises à jour /run/dnsmasq/docker.hosts lorsque les conteneurs s'arrêtent/démarrent
  • Après une mise à jour, dnsthing exécute systemctl restart dnsmasq_docker
  • dnsmasq_docker exécute dnsmasq à l'aide de la configuration ci-dessus, lié à une interface de pont local avec l'adresse 172.31.255.253.
  • Le processus dnsmasq "principal" sur mon système, géré par NetworkManager, utilise cette configuration de /etc/NetworkManager/dnsmasq.d/dockerdns:

    server=/docker/172.31.255.253
    

    Cela indique à dnsmasq de passer toutes les demandes d'hôtes dans le .docker domaine vers le docker_dnsmasq un service.

Cela nécessite évidemment un peu de configuration pour tout mettre ensemble, mais après cela, cela semble fonctionner:

$ ping -c1  mysql.bridge.docker
PING mysql.bridge.docker (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.087 ms

--- mysql.bridge.docker ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.087/0.087/0.087/0.000 ms
12
larsks

Comme répondu ici il existe une solution logicielle pour cela, copiant la réponse:


Il existe une application open source qui résout ce problème, elle s'appelle DNS Proxy Server

Il s'agit d'un serveur DNS qui résout les noms d'hôte des conteneurs, et lorsqu'il ne peut pas résoudre un nom d'hôte, il peut le résoudre à l'aide de serveurs de noms publics.

Démarrez le serveur DNS

$ docker run --hostname dns.mageddo --name dns-proxy-server -p 5380:5380 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /etc/resolv.conf:/etc/resolv.conf \
defreitas/dns-proxy-server

Il sera automatiquement défini comme votre DNS par défaut (et reviendra à l'original lorsqu'il s'arrêtera).

Démarrez votre conteneur pour le test

docker-compose up

docker-compose.yml

version: '2'
services:
  redis:
    container_name: redis
    image: redis:2.8
    hostname: redis.dev.intranet
    network_mode: bridge # that way he can solve others containers names even inside, solve elasticsearch, for example
  elasticsearch:
    container_name: elasticsearch
    image: elasticsearch:2.2
    hostname: elasticsearch.dev.intranet

Résolvez maintenant les noms d'hôte de vos conteneurs

de l'hôte

$ nslookup redis.dev.intranet
Server:     172.17.0.2
Address:    172.17.0.2#53

Non-authoritative answer:
Name:   redis.dev.intranet
Address: 172.21.0.3

d'un autre conteneur

$ docker exec -it redis ping elasticsearch.dev.intranet
PING elasticsearch.dev.intranet (172.21.0.2): 56 data bytes

Il résout également les noms d'hôtes Internet

$ nslookup google.com
Server:     172.17.0.2
Address:    172.17.0.2#53

Non-authoritative answer:
Name:   google.com
Address: 216.58.202.78
9
deFreitas

La façon la plus simple de le faire est d'ajouter des entrées à votre fichier d'hôtes

  • pour linux: ajoutez 127.0.0.1 docker_a docker_b vers le fichier/etc/hosts
  • pour mac: similaire à linux mais utilise l'ip de la machine virtuelle docker-machine ip default
3
jazgot

Pour résoudre spécifiquement ce problème, j'ai créé une simple injection de domaine "etc/hosts" outil qui résout les noms des conteneurs Docker locaux sur l'hôte. Exécutez simplement:

docker run -d \
    -v /var/run/docker.sock:/tmp/docker.sock \
    -v /etc/hosts:/tmp/hosts \
    --name docker-hoster \
    dvdarias/docker-hoster

Vous pourrez accéder à un conteneur en utilisant le container name, hostname, container id et vía le network aliases ils ont déclaré pour chaque réseau.

Les conteneurs sont automatiquement enregistrés lorsqu'ils démarrent et retirés lorsqu'ils sont en pause, morts ou arrêtés.

2
David Darias

Semblable à @larsks, j'ai écrit un script Python aussi mais je l'ai implémenté en tant que service. Le voici: https://github.com/nicolai-budico/dockerhosts

Il lance dnsmasq avec le paramètre --hostsdir=/var/run/docker-hosts et met à jour le fichier /var/run/docker-hosts/hosts chaque fois qu'une liste de conteneurs en cours d'exécution était modifiée. Une fois le fichier /var/run/docker-hosts/hosts est modifié, dnsmasq met automatiquement à jour son mappage et le conteneur devient disponible par nom d'hôte en une seconde.

$ docker run -d --hostname=myapp.local.com --rm -it ubuntu:17.10
9af0b6a89feee747151007214b4e24b8ec7c9b2858badff6d584110bed45b740

$ nslookup myapp.local.com
Server:         127.0.0.53
Address:        127.0.0.53#53

Non-authoritative answer:
Name:   myapp.local.com
Address: 172.17.0.2

Il existe des scripts d'installation et de désinstallation. Il vous suffit de permettre à votre système d'interagir avec cette instance dnsmasq. Je me suis inscrit dans résolu par systemd:

$ cat /etc/systemd/resolved.conf

[Resolve]
DNS=127.0.0.54
#FallbackDNS=
#Domains=
#LLMNR=yes
#MulticastDNS=yes
#DNSSEC=no
#Cache=yes
#DNSStubListener=udp
1
Nicolai