/ docker

Access docker containers using dns

Docker is great. Docker is awesome. But docker could be better for local development. the port forwarding is handy for production, but not for development. would't it be awesome to just have to type my-laravel-test.dev.localhost instead of localhost:8083 ?(because you run multiple webservers. your a webdevelopper)

Well then, lets get to it!

Setup

Network

We'll first need to setup a network in docker. Why not the default? 2 things:
1.Docker won't allow us to set a fixed ip if we don't specify a network
2.It's waaayy cleaner this way. Not every upstart_pony or youthful_hamilton needs to be accessable using dns

So a network is setup as followed:

docker network create --subnet=172.20.0.0/16 with-dns

Feel free to change the subnet, but we'll need it later!

Yaay! We've created a new network that can be used by other containers using the --net with-dns

DNS

For this we'll be using the awesome docker container https://github.com/phensley/docker-dns. It's a python script in a container that monitors the docker.sock for new containers.

Now the container run command:

docker run -dit --restart unless-stopped --name dns --net with-dns --ip 172.20.0.2 -v /var/run/docker.sock:/docker.sock phensley/docker-dns     --domain dev.localhost

That's a whole lot of command line! I'll explain:

  • -dit means detatch, interactive, tty. witch means, run in the background with an active tty.
  • --restart unless-stopped Means that this docker container will autostart and restart when crashed, unless it's manually stopped
  • --name dns the pretty docker container name
  • --net with-dns this container should be in our with-dns network
  • --ip 172.20.0.2 with this fixed ip.
  • -v /var/run/docker.sock:/docker.sock mount the local docker.sock to this container so docker-dns knows all the containers in with-dns
  • --domain dev.local Our domain name. Change at will!

To test if it worked, we'll spinup a simple docker image:

docker run --rm --name nginx --net with-dns nginx

and now if we run host against our new dns server:

[S]$ host nginx.dev.local 172.20.0.2
Using domain server:
Name: 172.20.0.2
Address: 172.20.0.2#53
Aliases: 

nginx.dev.local has address 172.20.0.4

🎉 Great success! 🎉

local resolv

so now for the tricky part. We need to use our new DNS server.

As you know, DNS queries on linux are mostly handled by the /etc/resolv.conf file (There are some exceptions). Now, uf you use any modern linux distro, most of the time you'll have something like NetworkManager. Now, NetworkManager (as the name implies) manages all network connections in your system. From your LAN port to your WiFi, From VPN to Bluetooth PtP, .. it does it all. And, in my opinion, quite good!

What NetworkManager (from hereon NM) also handles, is DNS.

In most of the configurations, NM places the recieved dns nameservers in the resolv.conf file, but in some configurations it runs its own Dnsmasq as primary dns server. Dnsmasq then relays dns requests to multiple dns servers or very specific dns servers. That's what we want!

First, we need to configure NM to run it's dns server. It may be already configured for you if your /etc/resolv.conf contains a nameserver 127.0.0.1 entry. If so continue to step 2.

1. Open up the file (as root) /etc/NetworkManager/conf.d/10-dns.conf (It shoud not exist) and add the following content:

[main]
dns=dnsmasq

This file activates the internal dns server.

2. Now we need to add our docker dns server to dnsmasq

Open up the file (as root) /etc/NetworkManager/dnsmasq.d/10-docker-dns.conf and enter the following content:

# *.dev.local
server=/dev.local/172.20.0.2

This basicly tells dnsmasq "For domains ending with dev.local, use the dns server 172.20.0.2!"

3. Now restart NM:

service NetworkManager restart

and check your /etc/resolv.conf:

cat /etc/resolv.conf 
# Generated by NetworkManager
search home telenet.be #trivial
nameserver 127.0.0.1 # That's what whe're after!

Use

Let's spinup that same simple docker image:

docker run --rm --name nginx --net with-dns nginx

And when you ping nginx.dev.local you should get something like:

[S]$ ping nginx.dev.local
PING nginx.dev.local (172.20.0.4) 56(84) bytes of data.
64 bytes from 172.20.0.4 (172.20.0.4): icmp_seq=1 ttl=64 time=0.070 ms
64 bytes from 172.20.0.4 (172.20.0.4): icmp_seq=2 ttl=64 time=0.090 ms
64 bytes from 172.20.0.4 (172.20.0.4): icmp_seq=3 ttl=64 time=0.060 ms
^C
--- nginx.dev.local ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2015ms
rtt min/avg/max/mdev = 0.060/0.073/0.090/0.014 ms

And if we go to http://nginx.dev.local:
Screenshot-from-2018-04-11-23-43-48


If you like what I write, there 's an error or just want to say Hi: subutux on twitter