42

I have the Docker version 1.10 with embedded DNS service.

I have created two service containers in my docker-compose file. They are reachable each other by hostname and by IP, but when I would like reach one of them from the host machine, it doesn't work, it works only with IP but not with hostname.

So, is it possible to access a docker container from the host machine by it's hostname in the Docker 1.10, please?

Update:

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

then I start it by command: docker-compose up --force-recreate

when I run:

  • docker exec -i -t docker_a ping -c4 docker_b - it works
  • docker exec -i -t docker_b ping -c4 docker_a - it works
  • ping 172.19.0.2 - it works (172.19.0.2 is docker_b's ip)
  • ping docker_a - fails

The result of the docker network inspect test_default is

[
    {
        "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": {}
    }
]
RonU
  • 5,525
  • 3
  • 16
  • 13
Adam Bernau
  • 729
  • 2
  • 6
  • 12
  • can you elaborate? what commands do you use, and what output do you get? – user2915097 Mar 06 '16 at 16:08
  • Yes of course, thanks for it. docker-compose.yml – Adam Bernau Mar 06 '16 at 16:33
  • You might need to manually add it to your hosts file – Xiongbing Jin Mar 06 '16 at 17:01
  • 2
    @warmoverflow: Yes, it's possible to do it this way, but IP addresses are assigned dynamically to containers. Than is necessary to update the hosts file manually for each change :-(. So I would like to ask if is it possible to solve it without modification of the hosts file or using an extra discovery service? – Adam Bernau Mar 06 '16 at 17:32
  • I searched around and it does not seem possible without third party tool or some scripts. Why do you need to access containers directly from host without any port mapping? – Xiongbing Jin Mar 06 '16 at 17:34
  • @warmoverflow: I don't need it for production, but for development. I need it for debugging and dev tools integration. – Adam Bernau Mar 06 '16 at 17:51
  • There's no easy way to do this yet. – dnephin Mar 07 '16 at 21:21
  • what's docker host environment ? since it needs to be accessed from host, it needs extra service in host. If you container name is "google.com", how do you manage to differ the real ? It needs to co-exist your host system. – Larry Cai Mar 31 '16 at 08:33

5 Answers5

16

As answered here there is a software solution for this, called DNS Proxy Server.

$ sudo ./dns-proxy-server

$ docker run --rm --hostname nginx.dev nginx
$ ping nginx.dev
PING nginx.dev (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4 (172.17.0.4): icmp_seq=1 ttl=64 time=0.043 ms
64 bytes from 172.17.0.4 (172.17.0.4): icmp_seq=2 ttl=64 time=0.022 ms
deFreitas
  • 4,196
  • 2
  • 33
  • 43
  • 2
    It does not work unless I create the container with --hostname. I don't wish modify the setup of running containers. It should work with default hostname i.e container name like it does from inside containers. Is there a way? – Dojo May 25 '20 at 11:03
14

To specifically solve this problem I created a simple "etc/hosts" domain injection tool that resolves names of local Docker containers on the host. Just run:

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

You will be able to access a container using the container name, hostname, container id and vía the network aliases they have declared for each network.

Containers are automatically registered when they start and removed when they are paused, dead or stopped.

David Darias
  • 570
  • 6
  • 9
  • Excellent product! It would be nice if it were a rootless container though, and just used docker-socket-proxy to access the socket API (or if the script ran on docker-socket-proxy itself). – Shōgun8 Jan 30 '20 at 19:47
13

Here's what I do.

I wrote a Python script called dnsthing, which listens to the Docker events API for containers starting or stopping. It maintains a hosts-style file with the names and addresses of containers. Containers are named <container_name>.<network>.docker, so for example if I run this:

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

I get this:

172.17.0.2 mysql.bridge.docker

I then run a dnsmasq process pointing at this hosts file. Specifically, I run a dnsmasq instance using the following configuration:

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

And I run the dnsthing script like this:

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

So:

  • dnsthing updates /run/dnsmasq/docker.hosts as containers stop/start
  • After an update, dnsthing runs systemctl restart dnsmasq_docker
  • dnsmasq_docker runs dnsmasq using the above configuration, bound to a local bridge interface with the address 172.31.255.253.
  • The "main" dnsmasq process on my system, maintained by NetworkManager, uses this configuration from /etc/NetworkManager/dnsmasq.d/dockerdns:

    server=/docker/172.31.255.253
    

    That tells dnsmasq to pass all requests for hosts in the .docker domain to the docker_dnsmasq service.

This obviously requires a bit of setup to put everything together, but after that it seems to Just Work:

$ 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
larsks
  • 277,717
  • 41
  • 399
  • 399
  • 1
    This looks pretty interesting, thanks, but there are some holes in my understanding... where does the `dnsmasq_docker` thing come in? – sjmeverett Jul 04 '16 at 11:01
4

The easiest way to do this is to add entries to your hosts file

  • for linux: add 127.0.0.1 docker_a docker_b to /etc/hosts file
  • for mac: similar to linux but use ip of virtual machine docker-machine ip default
jazgot
  • 1,943
  • 14
  • 25
1

Similar to @larsks, I wrote a Python script too but implemented it as service. Here it is: https://github.com/nicolai-budico/dockerhosts

It launches dnsmasq with parameter --hostsdir=/var/run/docker-hosts and updates file /var/run/docker-hosts/hosts each time a list of running containers was changed. Once file /var/run/docker-hosts/hosts is changed, dnsmasq automatically updates its mapping and container become available by hostname in a second.

$ 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

There are install and uninstall scripts. Only you need is to allow your system to interact with this dnsmasq instance. I registered in in systemd-resolved:

$ cat /etc/systemd/resolved.conf

[Resolve]
DNS=127.0.0.54
#FallbackDNS=
#Domains=
#LLMNR=yes
#MulticastDNS=yes
#DNSSEC=no
#Cache=yes
#DNSStubListener=udp
Nicolai
  • 5,489
  • 1
  • 24
  • 31