Some interesting understandings after playing with docker container DNS setting.

Let start with a simple docker container: docker run --rm --name container1 -it busybox /bin/sh .

In this container1 terminal, run cat /etc/resolv.conf.

/ # cat /etc/resolv.conf 
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 192.168.10.1

In the host machine, run cat /etc/resolv.conf.

# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients to the
# internal DNS stub resolver of systemd-resolved. This file lists all
# configured search domains.
#
# Run "systemd-resolve --status" to see details about the uplink DNS servers
# currently in use.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 127.0.0.53
options edns0

Problem 1: the DNS ip in host machine is 127.0.0.53 while in the container1 docker container, it is 192.168.10.1.

This is due to systemd-resolve service, a DNS proxy service, which caches DNS data to speedup DNS reverse lookup in the host machine.

To reveal information of this service, use systemd-resolve command.

sudo systemd-resolve --status
Global
          DNSSEC NTA: 10.in-addr.arpa
                      16.172.in-addr.arpa
                      168.192.in-addr.arpa
                      17.172.in-addr.arpa
                      18.172.in-addr.arpa
                      19.172.in-addr.arpa
                      20.172.in-addr.arpa
                      21.172.in-addr.arpa
                      22.172.in-addr.arpa
                      23.172.in-addr.arpa
                      24.172.in-addr.arpa
                      25.172.in-addr.arpa
                      26.172.in-addr.arpa
                      27.172.in-addr.arpa
                      28.172.in-addr.arpa
                      29.172.in-addr.arpa
                      30.172.in-addr.arpa
                      31.172.in-addr.arpa
                      corp
                      d.f.ip6.arpa
                      home
                      internal
                      intranet
                      lan
                      local
                      private
                      test

Link 143 (vetha8e6e15)
      Current Scopes: none
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no

Link 97 (br-8751bfcd84e3)
      Current Scopes: none
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no

Link 96 (veth4b35504)
      Current Scopes: none
       LLMNR setting: yes
MulticastDNS setting: no
      DNSSEC setting: no
    DNSSEC supported: no

Link 94 (vethbedcec0)
      Current Scopes: none

Not found 192.168.10.1 entry from the result. Try more with sudo /run/systemd/resolve/resolv.conf. The result sounds very interesting.

sudo cat /run/systemd/resolve/resolv.conf
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 192.168.10.1

Now 192.168.10.1 is exactly what we want. Docker find this IP address and assign to the docker machine while creation.


How does the dynamic network connect/disconnect work?

Now, please keep the container1 container run before continue.

Create a new network named my-net with docker network create my-net.

Connect container1 with my-net via docker network connect my-net container1.

Switch back to the container1 terminal, and re-run cat /etc/resolv.conf. The result changes

/ # cat /etc/resolv.conf 
# This file is managed by man:systemd-resolved(8). Do not edit.
#
# This is a dynamic resolv.conf file for connecting local clients directly to
# all known uplink DNS servers. This file lists all configured search domains.
#
# Third party programs must not access this file directly, but only through the
# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,
# replace this symlink by a static file or a different symlink.
#
# See man:systemd-resolved.service(8) for details about the supported modes of
# operation for /etc/resolv.conf.

nameserver 192.168.10.1
/ # cat /etc/resolv.conf 
nameserver 127.0.0.11
options ndots:0

The reason is simple and mentioned carefully in docker official docs.

Note: The DNS server is always at 127.0.0.11.

Docker maintains an embedded DNS server when user-defined network is in-use.


Test the embedded DNS server

Start another docker container with docker run --rm -it --network my-net ubuntu /bin/bash.

In this ubuntu image container terminal, run apt update && apt install -yq dnsutils whois.

Now, in this ubuntu image container terminal, run following commands to test the embedded DNS server.

root@0b0b0c18adaf:/# cat /etc/resolv.conf 
nameserver 127.0.0.11
options ndots:0

root@0b0b0c18adaf:/# dig @127.0.0.11 container1

; <<>> DiG 9.11.3-1ubuntu1.10-Ubuntu <<>> @127.0.0.11 container1
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 8179
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;container1.			IN	A

;; AUTHORITY SECTION:
.			10800	IN	SOA	a.root-servers.net. nstld.verisign-grs.com. 2019111800 1800 900 604800 86400

;; Query time: 54 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Mon Nov 18 09:55:05 UTC 2019
;; MSG SIZE  rcvd: 114

root@0b0b0c18adaf:/# dig container1

; <<>> DiG 9.11.3-1ubuntu1.10-Ubuntu <<>> container1
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 62239
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;container1.			IN	A

;; AUTHORITY SECTION:
.			10774	IN	SOA	a.root-servers.net. nstld.verisign-grs.com. 2019111800 1800 900 604800 86400

;; Query time: 43 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Mon Nov 18 09:55:31 UTC 2019
;; MSG SIZE  rcvd: 114

root@0b0b0c18adaf:/# whois 127.0.0.11
getaddrinfo(whois.arin.net): Servname not supported for ai_socktype

Happy coding!