How should systemd-resolved and docker interact?

Posted on

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.

Leave a Reply

Your email address will not be published. Required fields are marked *