-
Notifications
You must be signed in to change notification settings - Fork 18.9k
Description
Description
- relates to daemon/config: change DNSConfig.DNS to a []net.IP #46803 (comment)
- slightly related: [RFC] Add DNS configuration to /info endpoint #35506
While looking working on #46803, I noticed that we're not very consistent with "defaults" configured on the daemon.
- For log-driver (and options), we bake the defaults into the container when it's created
- We're not doing that for DNS; default DNS is not baked in the container, and thus updated if the daemon is restarted with new DNS settings
I think this was by design, so that a container without an explicit DNS configured can be updated to follow the daemon's defaults (or the host's DNS servers, if no default is set on the daemon). However, it makes it hard to discover what DNS is used for a container.
If the daemon was started with --dns 1.1.1.1, then the container does use 1.1.1.1 (as can be seen for a container on the default bridge network, and checking its /etc/resolv.conf);
docker run --rm busybox cat /etc/resolv.conf
nameserver 1.1.1.1But inspecting a container won't show that in the config;
docker inspect --format '{{.HostConfig.Dns}}' defaultdns
[]Whereas manually specifying the --dns does get baked into the container;
docker create --dns 2.2.2.2 --name customdns busybox
docker inspect --format '{{.HostConfig.Dns}}' customdns
[2.2.2.2]To verify that the DNS is not "baked" into containers without an explicit --dns set;
On a docker daemon started with --dns 1.1.1.1;
docker run -d --restart=always --name mycontainer nginx:alpine
docker exec mycontainer cat /etc/resolv.conf
nameserver 1.1.1.1After stopping the container, and restarting with a different DNS (--dns 8.8.8.8), the existing container is updated with the new DNS;
docker exec mycontainer cat /etc/resolv.conf
nameserver 8.8.8.8For the default bridge network, it's possible for the user to verify what DNS is used, either by checking its /etc/resolv.conf, or from nslookup output;
docker exec mycontainer nslookup google.com
Server: 8.8.8.8
Address: 8.8.8.8:53
Non-authoritative answer:
Name: google.com
Address: 142.251.36.14
Non-authoritative answer:
Name: google.com
Address: 2a00:1450:400e:810::200eHowever, when using a custom network, the resolver inside the container will be the embedded DNS, which makes it not possible to discover what "upstream" DNS servers are used;
docker network create mynetwork
a527a8903e46fdbcf16e5aa4c40a2c38e823bfcaa1e47449de09e7ad737832e4
docker run --rm --network=mynetwork alpine cat /etc/resolv.conf
nameserver 127.0.0.11
options ndots:0
docker run --rm --network=mynetwork alpine nslookup google.com
Server: 127.0.0.11
Address: 127.0.0.11:53
Non-authoritative answer:
Name: google.com
Address: 142.251.36.14
Non-authoritative answer:
Name: google.com
Address: 2a00:1450:400e:801::200ePossible improvements
improve generated /etc/resolv.conf
As we are generating the container's /etc/resolv.conf, a "quick win" would be include some comments in the generated file;
- include a comment that indicates the file was generated by docker; this can apply to both the default
bridgenetwork and for custom networks - include the list of "upstream" DNS servers that the daemon has configured
- a comment describing the behavior if the file is updated inside the container (we allow the file to be edited, but if edited, we will no longer update the file (we check if the checksum changed))
For "inspiration", here's an example of /etc/resolv.conf on a Linux machine with systemd-resolved;
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.include DNS information in "inspect" output
Having this information surface as part of inspect becomes more important if we decide to also use the embedded DNS for the default bridge network, as in that situation (as described above), it's more complicated for the user to obtain this information.
We should look if we can surface the DNS server(s) that are currently used for a container;
- if a custom DNS was configured for the container (
docker run --dns ..), these DNS servers would be the same as those in the config ("desired state") in.HostConfig.Dns - if no custom DNS was configured, this would show the list of DNS servers that the daemon uses as default. In case the embedded DNS is used, those would be the embedded DNS's "upstream" resolvers
- ❓ do we need an indication if
/etc/resolv.confinside the container was manually modified? In that case, we stop managing the container's DNS config, so we may not be able to provide the "correct" information.
consider making DNS "updatable" through docker container update
The docker container update (docker update shorthand) command currently does not allow for the DNS settings of a container to be updated.
- We can consider adding this to the list of options that can be updated for existing containers.
- If we do, we must also provide a way to unset the config (i.e., being able for a container to use the daemon's default)
- For UX, we should look at
docker service update, which has a better approach for mutating properties (through--<some-option>-add/--<some-option>-rm)
consider making DNS "reloadable"
We currently configure the list of DNS servers to use as default during daemon startup. This list can either originate from the host's resolvers (we parse /etc/resolv.conf), or from user-config (daemon.json or the --dns flags).
- As we already have code in place to update container's DNS settings (which we do during restart), we should look if it's possible to update these settings at runtime without requiring a full restart of the daemon.
- This feature could potentially be used "dynamically"; on systems with "dynamic" networks (laptop switching WiFI networks) we could use this to automatically update container configs when detecting network changes. Perhaps that part may be best left to external systems to "trigger", but perhaps the daemon itself could also watch for changes
- For manual changes to the config (updating
daemon.json), this can be used by the user throughsystemctl reload docker.serviceorSIGHUP dockerd;moby/contrib/init/systemd/docker.service
Line 14 in 93fffa2
ExecReload=/bin/kill -s HUP $MAINPID