Name resolution failed. The first job is to decide whether DNS is broken or the network is, because they look identical from the application's point of view.
ping -c1 1.1.1.1 # raw IP, no DNS involved
getent hosts example.com
| Result | Meaning |
|---|---|
| IP works, name fails | DNS. Continue below |
| Both fail | Routing or firewall. DNS is a symptom |
| Both work | Intermittent, or the application has its own resolver |
getent hosts is better than ping for testing names, because it uses the same NSS path as the rest of the system, including /etc/hosts and any module configured in nsswitch.conf.
What is the resolver configured to use?
cat /etc/resolv.conf
nameserver 127.0.0.53
options edns0 trust-ad
search .
127.0.0.53 is systemd-resolved's stub listener, so this file is not the real configuration:
resolvectl status
Link 2 (eth0)
Current Scopes: DNS
Protocols: +DefaultRoute
Current DNS Server: 10.0.0.2
DNS Servers: 10.0.0.2
An empty DNS Servers list means the link never received servers, usually because DHCP failed or a static configuration is incomplete.
If /etc/resolv.conf has no nameserver line at all, nothing is configured and every lookup fails immediately.
Test upstream directly
dig +short @1.1.1.1 example.com
dig +short @10.0.0.2 example.com # your configured server
An answer from 1.1.1.1 but not from the configured server means that server is unreachable or broken. No answer from either means outbound UDP 53 is blocked, which is common on hardened networks and in some cloud security groups.
sudo ss -ulpn | grep :53
sudo nft list ruleset 2>/dev/null | grep -i 53
systemd-resolved
sudo systemctl status systemd-resolved
sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches
A broken symlink is a frequent cause:
ls -l /etc/resolv.conf
It should point at /run/systemd/resolve/stub-resolv.conf. Something that overwrote it with a plain file, often a VPN client or a container tool, breaks the integration. Restore it:
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
Set servers explicitly where DHCP does not supply them:
sudo resolvectl dns eth0 1.1.1.1 1.0.0.1
For persistence, use netplan or /etc/systemd/resolved.conf. Editing /etc/resolv.conf by hand does not survive, because it is regenerated.
Containers
Docker copies the host's DNS configuration, with one important exception: it strips loopback addresses, because 127.0.0.53 inside a container refers to the container, not the host. If the host uses systemd-resolved and Docker cannot find a real upstream, it falls back to 8.8.8.8, which fails on networks that block external DNS.
docker run --rm alpine cat /etc/resolv.conf
docker run --rm alpine nslookup example.com
Set it explicitly:
// /etc/docker/daemon.json
{ "dns": ["10.0.0.2", "1.1.1.1"] }
sudo systemctl restart docker
Or per container:
docker run --dns 10.0.0.2 myapp
In Kubernetes the equivalent is CoreDNS:
kubectl -n kube-system get pods -l k8s-app=kube-dns
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=50
kubectl run -it --rm dnstest --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default
A Pod's /etc/resolv.conf points at the cluster DNS Service, so a failure there affects everything at once.
The search domain trap
search internal.acme.com acme.com
options ndots:5
With ndots:5, any name containing fewer than five dots is first tried with each search domain appended. example.com becomes example.com.internal.acme.com, then example.com.acme.com, then finally example.com. Each failed attempt costs a round trip.
This is the default inside Kubernetes Pods and is a well-known source of slow external lookups. Fix it per Pod:
spec:
dnsConfig:
options:
- name: ndots
value: "2"
Or use a fully qualified name with a trailing dot, example.com., which skips the search list entirely.
A checklist
ping 1.1.1.1versusgetent hosts example.com. Separate DNS from the network.cat /etc/resolv.conf. Nonameserverline means nothing is configured.127.0.0.53→resolvectl statusfor the real servers.dig @1.1.1.1 example.comto test upstream directly.- No answer from anything → outbound port 53 is blocked.
ls -l /etc/resolv.confshould be a symlink on systemd hosts.- Containers → check
/etc/resolv.confinside; setdnsindaemon.json. - Slow external lookups in Kubernetes →
ndots, or a trailing dot on the name.
Frequently Asked Questions
How do I tell whether DNS or the network is broken?
Ping a raw IP such as 1.1.1.1, which involves no name resolution, and then resolve a name with getent hosts example.com. If the IP responds and the name does not, the problem is DNS. If neither works, it is routing or a firewall and DNS is simply the first thing to notice. Use getent rather than ping for the name test, because it follows the same NSS path as the rest of the system, including /etc/hosts.
Why does /etc/resolv.conf show 127.0.0.53?
That is the systemd-resolved stub listener, a local resolver that forwards to the real upstream servers. So the file tells you very little; resolvectl status shows the actual DNS servers per link. Editing /etc/resolv.conf by hand on such a system does not persist, because it is a symlink to a generated file. Configure servers with resolvectl dns <link> <ip>, or persistently through netplan or /etc/systemd/resolved.conf.
Why does DNS work on the host but not inside my container?
Docker copies the host's resolver configuration but strips loopback addresses, since 127.0.0.53 inside a container refers to the container itself rather than the host's resolver. On a systemd-resolved host that can leave Docker with nothing usable, so it falls back to 8.8.8.8, which fails on any network that blocks external DNS. Set real upstream servers in /etc/docker/daemon.json under dns, or pass --dns on individual containers.
What is ndots and why does it make lookups slow?
ndots sets how many dots a name must contain before the resolver tries it as-is rather than appending each search domain first. Kubernetes defaults Pods to ndots:5, so example.com, having one dot, is first tried as example.com.<namespace>.svc.cluster.local and several other variants before the real query happens. Each attempt is a round trip. Lower it with a dnsConfig option on the Pod, or use a fully qualified name with a trailing dot to bypass the search list.
What should I check first in a Kubernetes cluster?
CoreDNS. kubectl -n kube-system get pods -l k8s-app=kube-dns shows whether it is running, and its logs usually explain a cluster-wide failure. Test from a throwaway Pod with kubectl run -it --rm dnstest --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default, which resolves an in-cluster name and so tests the whole path. Because every Pod's resolver points at the same Service, a CoreDNS problem breaks name resolution everywhere at once, which makes it look like a network outage.