Verifying name resolution

DNS resolution for containers has always been rather straightforward. The container received the same DNS configuration as the host. However, with the advent of user-defined networks and the embedded DNS server, this has now become a little trickier. A common problem in many of the DNS issues I've seen is not understanding how the embedded DNS server works and how to validate that it's working correctly. In this recipe, we'll step through a container DNS configuration to validate which DNS server it is using to resolve specific namespaces.

Getting ready

In this recipe, we'll be using a single Docker host. It is assumed that Docker is installed and in its default configuration. You'll also need root-level access in order to inspect and change the host's networking and firewall configuration.

How to do it…

The standard DNS configuration for Docker without user-defined networks is to simply copy the DNS configuration from the host into the container. In these cases, the DNS resolution is straightforward:

user@docker1:~$ docker run -dP --name web1 jonlangemak/web_server_1
e5735b30ce675d40de8c62fffe28e338a14b03560ce29622f0bb46edf639375f
user@docker1:~$
user@docker1:~$ docker exec web1 more /etc/resolv.conf
# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver <your local DNS server>
search lab.lab
user@docker1:~$
user@docker1:~$ more /etc/resolv.conf
nameserver <your local DNS server>
search lab.lab
user@docker1:~$

In these cases, all DNS requests will go straight to the defined DNS server. This means that our container can resolve any DNS records that our host can:

user@docker1:~$ docker exec -it web1 ping docker2.lab.lab -c 2
PING docker2.lab.lab (10.10.10.102): 48 data bytes
56 bytes from 10.10.10.102: icmp_seq=0 ttl=63 time=0.471 ms
56 bytes from 10.10.10.102: icmp_seq=1 ttl=63 time=0.453 ms
--- docker2.lab.lab ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.453/0.462/0.471/0.000 ms
user@docker1:~$

Coupled with the fact that Docker will masquerade this traffic to the IP address of the host itself makes this a simple and easily maintainable solution.

However, this gets a little trickier when we start using user-defined networks. This is because user-defined networks provide for container name resolution. That is, one container can resolve the name of another container without the use of static or manual host file entries and linking. This is a great feature, but it can cause some confusion if you don't understand how the container receives its DNS configuration. For instance, let's now create a new user-defined network:

user@docker1:~$ docker network create -d bridge mybridge1
e8afb0e506298e558baf5408053c64c329b8e605d6ad12efbf10e81f538df7b9
user@docker1:~$

Let's now start a new container named web2 on this network:

user@docker1:~$ docker run -dP --name web2 --net 
mybridge1 jonlangemak/web_server_2
1b38ad04c3c1be7b0f1af28550bf402dcde1515899234e4b09e482da0a560a0a
user@docker1:~$

Now if we connect our existing web1 container to this bridge, we should find that web1 can resolve the container web2 by name:

user@docker1:~$ docker network connect mybridge1 web1
user@docker1:~$ docker exec -it web1 ping web2 -c 2
PING web2 (172.18.0.2): 48 data bytes
56 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.100 ms
56 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.086 ms
--- web2 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.086/0.093/0.100/0.000 ms
user@docker1:~$

The problem here is that in order to facilitate this, Docker had to change the DNS configuration of the web1 container. In doing so, it injects the embedded DNS server in the middle of a containers DNS request. So before, when we were talking directly to the hosts DNS server, we are now talking to the embedded DNS server:

user@docker1:~$ docker exec -t  web1 more /etc/resolv.conf
search lab.lab
nameserver 127.0.0.11
options ndots:0
user@docker1:~$

This is required for DNS resolution to containers to work, but it has an interesting side effect. The embedded DNS server reads the host's /etc/resolv.conf file and uses any name servers defined in that file as forwarders for the embedded DNS server. The net effect of this is that you don't notice the embedded DNS server since it's still forwarding requests it can't answer to the host's DNS server. However, it only programs these forwarders if they are defined. If they don't exist or are set to 127.0.0.1, then Docker programs the forwarders to be Google's public DNS server (8.8.8.8 and 8.4.4.4).

Although this makes good sense, there are rare circumstances in which your local DNS server happens to be 127.0.0.1. For instance, you happen to be running some type of local DNS resolver on the same host or using a DNS forwarder application such as DNSMasq. In those cases, there are some complications that can be caused by Docker forwarding the container's DNS requests off to the aforementioned external DNS servers instead of the one locally defined. Namely, internal DNS zones will no longer be resolvable:

user@docker1:~$ docker exec -it web1 ping docker2.lab.lab
ping: unknown host
user@docker1:~$

Note

This can also cause general resolution issues because it is common to block DNS traffic to external DNS servers preferring instead to force internal endpoints to use internal DNS servers.

In these scenarios, there are a couple of ways to address this. You can either run the container with a specific DNS server by passing the DNS flag at container runtime:

user@docker1:~$ docker run -dP --name web2 --net mybridge1 
--dns <your local DNS server> jonlangemak/web_server_2

Otherwise, you can set the DNS server at the Docker service level, which the embedded DNS server will then use as the forwarder:

ExecStart=/usr/bin/dockerd --dns=<your local DNS server>

In either case, if you're having container resolution issues, always check and see what the container has configured in its /etc/resolv.conf file. If it's 127.0.0.11, that indicates you're using the Docker embedded DNS server. If you are, and you're still having issues, make sure that you validate the host DNS configuration to determine what the embedded DNS server is consuming for a forwarder. If there isn't one defined or it's 127.0.0.1, then make sure that you tell the Docker service what DNS server it should be passing to containers in one of the two ways defined earlier.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset