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?