KubernetesCXIII · Kubernetes DNS Advanced TroubleshootingDNS advanced troubleshooting
ndots and search paths — the DNS resolution chain
What you'll learn
- Understand ndots and the search path
- Diagnose latency caused by short-name resolution
- Apply nodelocaldns to mitigate latency
- Apply the operational discipline of tuning ndots
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
ndots and the search path are the source of DNS latency in many Kubernetes deployments. This lesson walks the resolution chain, the latency implications, and the operational discipline.
The resolution chain
flowchart LR
A["Query: billing"] --> B{ndots check}
B -->|"fewer than 5 dots"| C[Search path]
C --> C1[billing.prod-app.svc.cluster.local]
C1 -->|NXDOMAIN| C2[billing.svc.cluster.local]
C2 -->|NXDOMAIN| C3[billing.cluster.local]
C3 -->|NXDOMAIN| D["Name as given, then upstream DNS"]
B -->|"5 or more dots, or trailing dot"| D
The resolution chain:
- The query is
billing— no dots, which is fewer than ndots:5, so the resolver treats it as unqualified. - The resolver tries the search path in order:
billing.prod-app.svc.cluster.localbilling.svc.cluster.localbilling.cluster.local
- If all return NXDOMAIN, the name is finally tried as given and goes to the upstream DNS.
billing.example.comhas two dots, still fewer than five, so it walks the same search path before the external lookup that was actually wanted.billing.example.com.ends in a dot. It is absolute, so the search path is skipped entirely — one query, regardless of ndots.
The rule is one-directional: a name with fewer
dots than ndots is tried against the search domains
first; a name with ndots dots or more, or a trailing
dot, is tried as an absolute name first.
ndots configuration
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
dnsConfig:
options:
- name: ndots
value: "2"
containers:
- name: app
image: myapp
The ndots option is the dot count at which a name
stops being treated as unqualified:
- Default: 5. A name with fewer than five dots is tried against the search domains first.
- Lower value: fewer names go through the
search path, so external names such as
api.example.comresolve in one query — at the cost of breaking any name that relied on the search path to be completed. - Higher value: more names go through the search path, so even long external names pay the full walk before the lookup that was wanted.
For most workloads, ndots:2 is a good balance: a
single-label Service name such as billing still
expands through the search path, while anything with
two or more dots is resolved directly.
The search path
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
dnsConfig:
searches:
- prod-app.svc.cluster.local
- svc.cluster.local
- cluster.local
containers:
- name: app
image: myapp
The search path can be customised. The default is:
<namespace>.svc.cluster.localsvc.cluster.localcluster.local
A custom search path can shorten the chain (e.g.,
add prod-app.local for a specific namespace).
The latency impact
flowchart LR
A["Pod: myapp"] -->|billing| B[4 DNS queries]
B -->|5-10ms each| C[20-40ms latency]
A -->|"billing.prod-app.svc.cluster.local."| D[1 DNS query]
D -->|5-10ms| E[5-10ms latency]
The latency:
- Short name (billing). 4 queries × 5-10ms = 20-40ms total latency.
- FQDN with a trailing dot (billing.prod-app.svc.cluster.local.). 1 query × 5-10ms = 5-10ms total latency.
The difference: roughly 4x latency reduction. Without the trailing dot the FQDN has four dots, still fewer than five, so it walks the search path too — the saving comes from making the name absolute, not from its length.
Mitigation: nodelocaldns
flowchart LR
A[Pod] -->|billing| B[nodelocaldns cache]
B -->|cache hit| C[Immediate response]
B -->|cache miss| D[CoreDNS]
D -->|response| B
B -->|cached| A
nodelocaldns (covered in the previous lesson) caches DNS responses at the node level. For cached queries, the latency is <1ms.
For applications that make many DNS queries (thousands per second), nodelocaldns is essential.
Mitigation: explicit FQDNs
# Use FQDN instead of short name
import psycopg2
conn = psycopg2.connect(
host="db.prod-data.svc.cluster.local.", # absolute FQDN
port=5432,
database="mydb"
)
Using fully qualified names in application code:
- Eliminates the search path overhead.
- Reduces the DNS query count by roughly 4x.
- Reduces DNS latency by roughly the same factor.
Write the trailing dot — db.prod-data.svc.cluster.local.
— so the name is absolute regardless of the Pod’s
ndots. The trade-off: the name must be correct; an
incorrect namespace in an absolute name fails outright
rather than falling back through the search path.
Quiz
Knowledge check · 4 questions
Q1. With `ndots:5`, what happens when a Pod resolves `api.example.com`?
Q2. Lowering `ndots` in a Pod's dnsConfig can break resolution of short Service names.
Q3. Reduce the DNS query amplification caused by short-name lookups in a high-throughput service.
A service in namespace prod-app connects to Redis using the host string `redis.prod-data`. After a scale-up from 200 to 3000 requests per second, p99 latency rises from 8ms to 60ms. CoreDNS is handling 12000 queries per second and its request duration histogram shows increased tail latency. The Pod's /etc/resolv.conf carries the default `options ndots:5`.
Q4. For a Pod in namespace prod-app with default settings, list in order the names the resolver tries for the query `redis.prod-data`, and explain why a trailing dot removes them.
Passing score: 75%. Answers are checked in this browser.
The operational discipline
ndots and search path tuning in production rests on five non-negotiable elements:
- Use FQDNs in application code. Eliminates the search path overhead.
- Install nodelocaldns. Caches at the node level.
- Tune ndots. ndots:2 is a good balance.
- Customise the search path. Add namespace-specific entries.
- Profile DNS latency. Measure before and after changes.
DNS latency is invisible until it isn’t. The discipline is to measure and tune.