Docker DNS

One of the reasons why I like Docker is that it makes development with external services much easier to do. If you are working with a microservices architecture it is a regular occurence that you want to work on service A, but you need access to service B somewhere in service A. Doing that with Docker, and more specifically docker-compose, is a cinch. I will not go into the details in this blog post, but essentialy you define your docker-compose.yml something like this

serviceb:
    image: username/serviceb

servicea:
    image: username/servicea
    links:
        - serviceb

When you execute docker-compose up servicea it will automatically start service B and make the IP of service B available in the service A container via an environment variable.

A small annoyance I had with this set-up was that whenever I wanted to connect to service B directly, I needed its IP not in a container but on the host machine. The default way to get access to its IP is by executing

docker inspect --format "{{ .NetworkSettings.IPAddress }}" <container_name>

The downside of this approach is that whenever I restart service B, it will get a new IP address, forcing me to look it up again. And I always forget the exact syntax for the format option, so I have to google it everytime.

Let’s fix that!

Enter tonistiigi/dnsdock. It is a Docker container that will act as a local DNS for your Docker containers.

The setup is pretty easy, just run

docker run -d -v /var/run/docker.sock:/var/run/docker.sock --name dnsdock -p 172.17.42.1:53:53/udp tonistiigi/dnsdock

This will expose your docker.sock inside the container so it has access to all the docker containers.

All you need to do now is add 172.17.42.1 as a DNS server in your OS. On Ubuntu 14.04 you can do this by adding nameserver 172.17.42.1 to /etc/resolvconf/resolv.conf.d/head and running sudo resolvconf -u.

By default the DNS will respond with the IP of a container on URLs of the form

<container-name>.<image-name>.docker

You can always override the image-name and container-name by providing the environment variables DNSDOCK_IMAGE and DNSDOCK_NAME to the container. Thus our docker-compose.yml would look like this

serviceb:
    image: username/serviceb
    environment:
        - DNSDOCK_NAME=serviceb-1
        - DNSDOCK_IMAGE=serviceb

We can now reach our service at serviceb-1.serviceb.docker, isn’t that handy?