Using the Add-Host Flag for DNS Mapping within Docker Containers
In a previous article about the docker run
command, one of my final thoughts was the following:
In this article, we covered quite a few options for the
docker run
command. However, while these options are key, they only scratch the surface of the available options todocker run
. Some of the options are complex enough to deserve an article unto themselves.
In today’s article, we are going to do just that: explore a single docker run
command option. Specifically, we will explore an option that allows us to change DNS within a container.
Today, we will explore the --add-host
flag.
What Does Add-Host Do?
The --add-host
flag is used to add a single host to IP mapping within a Docker container. This flag can be useful when you need to connect a service within a container to an external host.
To get an understanding of how this works, let’s use the --add-host
flag to map testing.example.com
to 10.0.0.1
.
We will be testing with a container named curl. This container has the curl
command preinstalled and set as the entrypoint. With this container, we can use the curl
command to connect to our test host.
Before we start adding the --add-host
flag, let’s see what happens if we use this curl container to connect to the testing.example.com
domain.
$ docker run --rm=True curl -I testing.example.com curl: (6) Could not resolve host: testing.example.com
We can see from the above, the curl
command returned an error Could not resolve host
. This is the typical error we would see when trying to reach a domain that does not have a DNS entry.
This example shows us what happens without any --add-host
flags added. Let’s see what happens when we use this flag to map testing.example.com
to 10.0.0.1
.
$ docker run --rm=True --add-host=testing.example.com:10.0.0.1 curl -I testing.example.com HTTP/1.1 200 OK Server: nginx Date: Fri, 17 Nov 2017 14:01:20 GMT Content-Type: text/html Content-Length: 97652 Last-Modified: Sun, 16 Jul 2017 11:29:52 GMT Connection: keep-alive Vary: Accept-Encoding ETag: "596b4e30-17d74" Accept-Ranges: bytes
Great! Now when our container reaches out to testing.example.com
, it is able to connect to our example host. This means our internal DNS resolution works; but how exactly does it work?
Understanding How Add-Host Works
To understand how the --add-host
flag works, let’s spin up a simple Ubuntu container and take a look around. We can do this by using the -i
(Interactive) and -t
(Pseudo-TTY) flags.
These flags will start the container in a mode that allows us to interact with the running process. The process in this case will be /bin/bash
; this gives us a shell within the container. With this shell, we can explore within the container itself.
$ docker run --rm=True --add-host=testing.example.com:10.0.0.1 -it ubuntu /bin/bash root@a87b1beb2eee:/#
With our shell startup successful, let’s start looking at this container’s configuration files. Specifically, let’s look at the configurations that drive DNS resolution. The first file we will look at is the /etc/nsswitch.conf
file.
The nsswitch.conf
file in Unix and Linux is used to define where and how the system will perform name service-related lookups. The specific setting we are interested in is the hosts
setting. The hosts
setting is used to define the sources and order used for hostname resolution.
root@a87b1beb2eee:/# cat /etc/nsswitch.conf # /etc/nsswitch.conf # # Example configuration of GNU Name Service Switch functionality. # If you have the `glibc-doc-reference' and `info' packages installed, try: # `info libc "Name Service Switch"' for information about this file. passwd: compat group: compat shadow: compat gshadow: files hosts: files dns networks: files protocols: db files services: db files ethers: db files rpc: db files netgroup: nis
In the above, we can see that the hosts
setting is set to files dns
. This setting means that for hostname resolution, the system will first consult files, then dns.
When our system is performing a DNS lookup, it will first reference local configuration files, such as /etc/hosts
. If the host is not found within /etc/hosts
, the system will then query the name servers defined within the /etc/resolv.conf
configuration file.
Something important to remember is that this methodology is the standard Linux setup. These steps are common for most Linux systems, not just containers.
What does this mean for the --add-host
flag? Well, it means that there are only two places Docker could change DNS resolution: either the /etc/hosts
file or the name servers referenced in /etc/resolv.conf
.
The most likely candidate is the /etc/hosts
file.
root@a87b1beb2eee:/# cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 10.0.0.1 testing.example.com 172.17.0.3 a87b1beb2eee
If we look at the /etc/hosts
file, we can see an interesting entry.
10.0.0.1 testing.example.com
It appears that the --add-host
flag places an entry into the /etc/hosts
file. What is interesting about this is that editing the /etc/hosts
file is a time-honored sysadmin trick. It has been used for many years to perform just this task: taking an unresolvable hostname and mapping it to a static IP.
!Sign up for a free Codeship Account
Using Add-Host to Override DNS Resolution
Another common use of the /etc/hosts
file is overriding normal DNS. Since files
is listed first within the /etc/nsswitch.conf
configuration file, the /etc/hosts
file is consulted before any traditional DNS name servers.
This means that it is possible to place an entry into the /etc/hosts
file that overrides an existing name. To experiment a little, let’s do this with Google’s domain.
To start our experiment, lLet’s take a look at what normally happens when we use our curl container to connect to google.com
.
$ docker run --rm=True curl -I google.com HTTP/1.1 301 Moved Permanently Location: http://www.google.com/ Content-Type: text/html; charset=UTF-8 Date: Fri, 17 Nov 2017 14:04:43 GMT Expires: Sun, 17 Dec 2017 14:04:43 GMT Cache-Control: public, max-age=2592000 Server: gws Content-Length: 219 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN
From the above, we can see a pretty typical response from google.com
. Now, let’s see what happens if we use the --add-host
flag to map google.com
to 10.0.0.1
.
$ docker run --rm=True --add-host=google.com:10.0.0.1 curl -I google.com HTTP/1.1 200 OK Server: nginx Date: Fri, 17 Nov 2017 14:05:52 GMT Content-Type: text/html Content-Length: 97652 Last-Modified: Sun, 16 Jul 2017 11:29:52 GMT Connection: keep-alive Vary: Accept-Encoding ETag: "596b4e30-17d74" Accept-Ranges: bytes
From the above, we can see that our --add-host
addition resulted in our curl
command to connect to our example host. What this shows is that the --add-host
flag can be used for more than mapping an unresolved hostname. It can be used to override traditional DNS as well.
This can be a useful method to force a container to connect to a specific host address.
Adding Multiple Entries
Another nice feature of this flag is that it can be specified multiple times.
$ docker run --rm=True --add-host=1.example.com:10.0.0.1 --add-host=2.example2.com:10.0.0.2 --add-host=3.example.com:10.0.0.3 ubuntu cat /etc/hosts 127.0.0.1 localhost ::1 localhost ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters 10.0.0.1 1.example.com 10.0.0.2 2.example.com 10.0.0.3 3.example.com 172.17.0.3 17796a2cb640
In the above example, we can see that specifying the --add-host
multiple times resulted in multiple entries within the /etc/hosts
file. This is true whether multiple hosts are specified (as shown) or if the same host is specified.
This is useful in cases where you may want to specify multiple manual host to IP mappings.
Summary
In this article, we explored the --add-host
flag available with the docker run
command. We also learned that Docker uses a time-honored sysadmin trick for the heavy lifting behind the --add-host
flag.
At this point though, you might be thinking, “This flag is interesting but how can it be used in the real world?”
When creating an application that uses another service, like Redis for example, I tend to have my application configured to reach out to the host of redis
. I then link a Redis container with that name to my application container. This means my container’s configuration is simple — it just references redis
. This works great when I can simply link the Redis container to my application container.
But what happens when the Redis instance can’t be “linked” or is even outside of your control? We would then have to configure the application to reach out to a specific host, somewhat complicating the application’s configuration.
The --add-host
flag can be a simple way to keep a simplistic application configuration while still enabling the application to connect to the remote instance.
Published on Web Code Geeks with permission by Ben Cane, partner at our WCG program. See the original article here: Using the Add-Host Flag for DNS Mapping within Docker Containers Opinions expressed by Web Code Geeks contributors are their own. |