Every Kubernetes pod gets a resolv.conf configured with ndots:5 by default: any name to resolve containing fewer than 5 dots gets tried first against each of the cluster’s search domains, before being attempted as-is. This detail, invisible under normal operation, silently multiplies the number of DNS queries for any resolution toward an external domain.

What resolv.conf actually contains in a pod

cat /etc/resolv.conf
# search default.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

ndots:5 means: if the name to resolve contains fewer than 5 dots, try each suffix from the search list first, in order, before trying the name as-is. api.example.com only contains 2 dots, well under the threshold of 5: resolution therefore attempts, in sequence, api.example.com.default.svc.cluster.local, api.example.com.svc.cluster.local, api.example.com.cluster.local, each a distinct DNS query that fails, before finally trying api.example.com as-is.

The real cost: up to 4 failed DNS queries before the right one

For an internal service name (backend.default.svc.cluster.local, 5 dots), this mechanism works as intended and resolves on the first attempt. For any external name (a third-party API, a SaaS service), every call pays the price of 3 to 4 DNS queries that systematically fail before the right one succeeds, latency added to every resolution, invisible as long as it stays a few milliseconds, but adding up on a service with high external call volume.

# Resolving an external domain with ndots:5:
# 4 wasted DNS queries before the right one
api.example.com.default.svc.cluster.local  → NXDOMAIN
api.example.com.svc.cluster.local          → NXDOMAIN
api.example.com.cluster.local              → NXDOMAIN
api.example.com                            → success

CoreDNS absorbs the traffic, but doesn’t eliminate it

Every one of these failed queries genuinely reaches CoreDNS, which has to answer (with an NXDOMAIN) before the pod’s resolver moves to the next attempt. On a cluster with high outbound call volume toward external domains, this 4x-to-5x multiplied DNS traffic becomes measurable CoreDNS load, sometimes enough to explain intermittent DNS latency no other cluster component accounts for.

Two fixes, two different trade-offs

Adding a trailing dot to the resolved name (api.example.com.) forces absolute resolution, entirely bypassing the search list: the query goes straight to the external domain, never attempting the internal suffixes. This fix has to happen in application code, on every call, a constraint that doesn’t always fit.

# Pod-level alternative: adjust ndots directly,
# without touching a single line of application code
apiVersion: v1
kind: Pod
spec:
  dnsConfig:
    options:
      - name: ndots
        value: "2"

Lowering ndots at the pod level (via dnsConfig) changes the global threshold: an external name with 2 dots or fewer jumps straight to absolute resolution, skipping the search list. The trade-off: a shortened internal service name (without its full .svc.cluster.local suffix) risks no longer resolving correctly if its dot count falls under the new threshold, a compromise to validate against the naming conventions actually used in the cluster.

Takeaway

Kubernetes’ default ndots:5 tries up to 4 internal search domains before any external DNS resolution, a cost invisible under normal operation but one that adds up in latency and CoreDNS load on a service with high outbound call volume. Forcing absolute resolution (trailing dot on the name) or adjusting ndots via dnsConfig fix the problem through two different paths, each with its own trade-off (code change versus risk on shortened internal names). One of the DNS details that matter the moment a Kubernetes migration has an application talking to high-volume external services.