Naturally, the next thing to consider after IPAM is name resolution. Regardless of scale, having some way to locate and identify containers by something other than an IP address becomes a necessity. Much like newer versions of Docker, Weave offers its own DNS service for resolving container names that live on Weave networks. In this recipe, we'll review the default configuration for WeaveDNS as well as show how it's implemented and some relevant configuration settings to get you up and running.
It is assumed that you're building off the lab we created in the first recipe of this chapter. It is also assumed that the hosts have Docker and Weave installed. Docker should be in its default configuration and Weave should be installed with all four hosts successfully peered together, as we did in the first recipe of this chapter.
If you've been following along up until this point in the chapter, you've already provisioned WeaveDNS. WeaveDNS comes along with the Weave router container and is enabled by default. We can see this by looking at the Weave status:
user@docker1:~$ weave status …<Additional output removed for brevity>… Service: dns Domain: weave.local. Upstream: 10.20.30.13 TTL: 1 Entries: 0 …<Additional output removed for brevity>…
When Weave provisions the DNS service, it starts with some sane defaults. In this case, it's detected that my hosts DNS server is 10.20.30.13
, and so it has configured that as an upstream resolver. It's also selected weave.local
as the domain name. If we start a container using the weave run syntax, Weave will make sure that the container is provisioned in a manner that allows it to consume this DNS service. For instance, let's start a container on the host docker1
:
user@docker1:~$ weave run -dP --name=web1 jonlangemak/web_server_1
c0cf29fb07610b6ffc4e55fdd4305f2b79a89566acd0ae0a6de09df06979ef36
user@docker1:~$ docker exec –t web1 more /etc/resolv.conf
nameserver 172.17.0.1
user@docker1:~$
After starting the container, we can see that Weave has configured the container's resolv.conf
file differently than Docker would have. Recall that Docker, by default, in nonuser-defined networks, will give a container the same DNS configuration as the Docker hosts itself. In this case, Weave has given the container a name server of 172.17.0.1
, which is, by default, the IP address assigned to the docker0
bridge. You might be wondering how Weave expects the container to resolve its own DNS system by talking to the docker0
bridge. The solution is quite simple. The Weave router container is run in host mode and has a service bound to port 53
:
user@docker1:~$ docker network inspect host …<Additional output removed for brevity>… "Containers": { "03e3e82a5e0ced0b973e2b31ed9c2d3b8fe648919e263965d61ee7c425d9627c": { "Name": "weave", …<Additional output removed for brevity>…
If we check the ports bound on the host, we can see that the weave router is exposing port 53
:
user@docker1:~$ sudo netstat -plnt Active Internet connections (only servers) …<some columns removed to increase readability>… Proto Local Address State PID/Program name tcp 172.17.0.1:53 LISTEN 2227/weaver
This means that the WeaveDNS service in the Weave container will be listening on the docker0
bridge interface for DNS requests. Let's start another container on the host docker2
:
user@docker2:~$ weave run -dP --name=web2 jonlangemak/web_server_2 b81472e86d8ac62511689185fe4e4f36ac4a3c41e49d8777745a60cce6a4ac05 user@docker2:~$ docker exec -it web2 ping web1 -c 2 PING web1.weave.local (10.32.0.1): 48 data bytes 56 bytes from 10.32.0.1: icmp_seq=0 ttl=64 time=0.486 ms 56 bytes from 10.32.0.1: icmp_seq=1 ttl=64 time=0.582 ms --- web1.weave.local ping statistics --- 2 packets transmitted, 2 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.486/0.534/0.582/0.048 ms user@docker2:~$
As long as both containers are on the Weave network and have the appropriate settings, Weave will automatically generate a DNS record with the containers name. We can view all the name records Weave is aware of using the weave status dns
command from any Weave-enabled host:
user@docker2:~$ weave status dns web1 10.32.0.1 86029a1305f1 12:d2:fe:7a:c1:f2 web2 10.44.0.0 56927d3bf002 e6:b1:90:cd:76:da user@docker2:~$
Here, we can see the container name, the IP address, the container ID, and the MAC address of the destination host's Weave network interface.
This works well but relies on the container being configured with the appropriate settings. This is another scenario where using the Weave CLI is rather helpful since it ensures that these settings are in place at container runtime. For instance, if we start another container on the host docker3
with the Docker CLI and then attach it to Docker, it won't get a DNS record:
user@docker3:~$ docker run -dP --name=web1 jonlangemak/web_server_1 cd3b043bd70c0f60a03ec24c7835314ca2003145e1ca6d58bd06b5d0c6803a5c user@docker3:~$ weave attach web1 10.36.0.0 user@docker3:~$ docker exec -it web1 ping web2 ping: unknown host user@docker3:~$
This doesn't work for two reasons. First, the container doesn't know where to look for Weave DNS, and it is trying to resolve it through the DNS server Docker provided. In this case, that's the one configured on the Docker host:
user@docker3:~$ docker exec -it 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 10.20.30.13 search lab.lab user@docker3:~$
Second, Weave did not register a record in WeaveDNS when the container was attached. In order for Weave to generate a record for the container in WeaveDNS, the container must be in the same domain. To do this, when Weave runs a container through its CLI, it passes the hostname of the container along with a domain name. We can mimic this behavior by provisioning a hostname when we run the container in Docker. For instance:
user@docker3:~$ docker stop web1
user@docker3:~$ docker rm web1
user@docker3:~$ docker run -dP --hostname=web1.weave.local
--name=web1 jonlangemak/web_server_1
04bb1ba21b692b4117a9b0503e050d7f73149b154476ed5a0bce0d049c3c9357
user@docker3:~$
Now when we attach the container to the Weave network, we should see a DNS record generated for it:
user@docker3:~$ weave attach web1 10.36.0.0 user@docker3:~$ weave status dns web1 10.32.0.1 86029a1305f1 12:d2:fe:7a:c1:f2 web1 10.36.0.0 5bab5eae10b0 ae:af:a6:36:18:37 web2 10.44.0.0 56927d3bf002 e6:b1:90:cd:76:da user@docker3:~$
You might have noticed that we now have two entries in WeaveDNS for the same container name. This is how Weave provides for basic load balancing within the Weave network. For instance, if we head back to the docker2
host, let's try and ping the name web1
a couple of different times:
user@docker2:~$ docker exec -it web2 ping web1 -c 1 PING web1.weave.local (10.32.0.1): 48 data bytes 56 bytes from 10.32.0.1: icmp_seq=0 ttl=64 time=0.494 ms --- web1.weave.local ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.494/0.494/0.494/0.000 ms user@docker2:~$ docker exec -it web2 ping web1 -c 1 PING web1.weave.local (10.36.0.0): 48 data bytes 56 bytes from 10.36.0.0: icmp_seq=0 ttl=64 time=0.796 ms --- web1.weave.local ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.796/0.796/0.796/0.000 ms user@docker2:~$ docker exec -it web2 ping web1 -c 1 PING web1.weave.local (10.32.0.1): 48 data bytes 56 bytes from 10.32.0.1: icmp_seq=0 ttl=64 time=0.507 ms --- web1.weave.local ping statistics --- 1 packets transmitted, 1 packets received, 0% packet loss round-trip min/avg/max/stddev = 0.507/0.507/0.507/0.000 ms user@docker2:~$
Note how the container is resolving to a different IP address during the second ping attempt. Since there are multiple records in WeaveDNS for the same name, we can provide basic load balancing functionality just using DNS. Weave will also track the state of the containers and pull dead containers out of WeaveDNS. For instance, if we kill the container on the host docker3
, we should see one of the web1
records fall out of DNS leaving only a single record for web1
:
user@docker3:~$ docker stop web1
web1
user@docker3:~$ weave status dns
web1 10.32.0.1 86029a1305f1 12:d2:fe:7a:c1:f2
web2 10.44.0.0 56927d3bf002 e6:b1:90:cd:76:da
user@docker3:~$
There are many different configuration options available to you for customizing how WeaveDNS works. To see the entire guide, check out the documentation at https://www.weave.works/docs/net/latest/weavedns/.