QUESTION :
This section specifies that a Docker container gets a copy of the host’s /etc/resolv.conf
. However, when i run a simple container on Fedora 34, i get a different result:
$ cat /etc/resolv.conf
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
...
nameserver 127.0.0.53
options edns0 trust-ad
search .
$ docker run --rm -it alpine /bin/sh
/ # cat /etc/resolv.conf
# This is /run/systemd/resolve/resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
...
nameserver 192.168.0.1
nameserver 192.168.0.2
search .
The docker container got nameservers of my primary interface maintained by systemd-resolved
:
$ resolvectl dns enp1s0
Link 2 (enp1s0): 192.168.0.1 192.168.0.2
This works when i want to access the Internet. But does this mean that Docker somehow integrates with systemd-resolved
?
Furthermore, i found that there’s a problem with running containers requiring my corporate VPN connection. As i understand, DNS requests go straight to my router (192.168.0.*) and not to the virtual interface set up by the VPN. I solved it somewhat artificially by adding --dns 127.0.0.53 --network host
flags to the docker run
command.
It won’t work with just the --dns
flag. Why is the host networking mode necessary? After all, 192.168.0.1 and 192.168.0.2 are not in the container’s network either and they work?
Lastly, i found this repository which seems to address the problem but i don’t quite get how it works. Could someone describe the matter more broadly?
ANSWER :
Yes, Docker certainly does “integrate” with systemd-resolved: By detecting 127.0.0.53
and then not using it. You can see the relevant code here:
if len(ns) == 1 && ns[0] == "127.0.0.53" {
pathAfterSystemdDetection = alternatePath
logrus.Infof("detected 127.0.0.53 nameserver, assuming systemd-resolved, so using resolv.conf: %s", alternatePath)
}
Docker then uses /run/systemd/resolve/resolv.conf, which is the non-stub-resolver file that systemd-resolved manages. If your DNS client properly integrates with systemd-resolved, its DNS servers should also show up in this file, but only while the connection is active.
Why does it not work without --network host
? Because addresses within 127.0.0.0/8 are only reachable on the same host (or, more accurately: network namespace). This is a critical security feature. Inside a different network namespace, 127.0.0.0/8 refers to the localhost in this namespace only. Different hosts are accessible like normal using Docker’s default NAT network.
The project you found is, in simple terms, a DNS resolver. So basically the same as systemd-resolved, except it’s programmed to listen on the Docker default bridge. The requests are delegated to systemd-resolved. In reality, it does some more stuff like resolving container names and whatnot.