23 Aug 22 13:49 +0000
How IP got determined inside docker container

There are few steps before an IP is determined inside docker container:

  • Check host override (/etc/hosts).
  • Select DNS server (/etc/resolv.conf).
  • Query records from DNS server.

Check host override

Host override has the first priority.

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
192.168.1.100	webserver
172.17.0.2	d17c57476cbd

The default content of host file comes from dockerd and is designed to be unable to modify during build time.

When running a contaner there is a --add-host flag to add records for host override, for example:

docker run -it --rm --add-host webserver:192.168.1.100 nicolaka/netshoot:latest

There is also a --add-host flag in docker build but it's only affect build time but not runtime: https://github.com/moby/moby/issues/34078.

Select DNS server

cat /etc/resolv.conf

search default.svc.cluster.local svc.cluster.local
nameserver 192.168.0.3
nameserver 10.120.20.53
nameserver 10.120.46.153
options ndots:2 timeout:2 attempts:2

The content of resolve file is generated by dockerd, dockerd has some flags to provide flexibility for DNS resolution, like --dns, --dns-search, --dns-opt.

For example, if you are using kubespray to provision Kubernetes cluster, there will be a config file at /etc/systemd/system/docker.service.d/docker-dns.conf on the nodes:

[Service]
Environment="DOCKER_DNS_OPTIONS=\
    --dns 192.168.0.3 --dns 10.120.20.53 --dns 10.120.46.153  \
    --dns-search default.svc.cluster.local --dns-search svc.cluster.local \
    --dns-opt ndots:2 --dns-opt timeout:2 --dns-opt attempts:2  \
"

The environment variable is used as:

cat /etc/systemd/system/docker.service

...
ExecStart=/usr/bin/dockerd \
          $DOCKER_OPTS \
          $DOCKER_STORAGE_OPTIONS \
          $DOCKER_DNS_OPTIONS
...

This will generate content as above inside containers.

dig

The dig command can be used to gather DNS information.

dig [server] [name] [type]

Example output:

dig github.com

; <<>> DiG 9.18.3 <<>> github.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56631
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: f45e722f7703ca3e (echoed)
;; QUESTION SECTION:
;github.com.			IN	A

;; ANSWER SECTION:
github.com.		30	IN	A	20.205.243.166

;; Query time: 84 msec
;; SERVER: 192.168.0.3#53(192.168.0.3) (UDP)
;; WHEN: Sat Sep 03 15:40:52 UTC 2022
;; MSG SIZE  rcvd: 77

dig will use the first DNS server in /etc/resolv.conf, if you need a different DNS server:

dig @192.168.0.3 github.com

If you need to query other type of DNS records, use:

dig @192.168.0.3 github.com MX

nslookup

Similar to dig command, nslookup command can also be used to gather DNS information.

nslookup github.com
nslookup github.com 192.168.0.3

nslookup can also query other types of DNS records, but uses a interactive mode, which I think is more complicated than dig so I'll just use dig instead.

And watch out, while dig uses the OS resolve libraries, nslookup uses is own internal ones: dns - dig vs nslookup - Unix & Linux Stack Exchange.

I recommend never using nslookup.

host

host is a replacement for nslookup and provides more options and detail:

host github.com
host github.com 192.168.0.3
host -t MX github.com 192.168.0.3

Loading comments...