Interactive · Kubernetes DNS
The architecture stays put; only its state changes. Thick grey lines are paths that always exist — the coloured line that lights on top is the one carrying this query. Look up a cluster name and the query never leaves the cluster. Look up an external name and the same line of code costs five queries.
A pod’s IP is assigned when it starts and gone when it dies. A rollout replaces every pod and every address; scale up, drain a node, fail a probe, and the set of addresses behind payments is different from what it was a minute ago. No config file can hold an IP, and nothing can be reached by remembering where it was last time.
A Service fixes half of that, putting a stable ClusterIP in front of a changing set of pods. But a ClusterIP
is still an address, allocated when the Service is created — and your code is written before that happens.
So the actual product of cluster DNS is a name you can predict. payments.shop.svc.cluster.local
follows mechanically from the Service name and the namespace, which means you can write it in a different repo,
on a different team, before the Service exists.
Kubernetes does have a discovery API — EndpointSlice — and almost nothing calls it directly. DNS
won because it is the one lookup every language and every binary already speaks. No SDK, no client library, no
sidecar, no code change: connect("payments") behaves the same from Go, Python, a JVM service,
curl, and a vendor binary you cannot recompile.
The cost is what this page traces. Choosing DNS means inheriting DNS’s semantics, including a resolver stub that assumes a name with few dots is a fragment needing a suffix. That assumption is free for payments. It is why db.corp.example costs five queries.
| # | Hop | What happens | Setting |
|---|
| Claim on this page | How to check it |
|---|---|
| ndots is 5, and you did not set it | kubectl exec <pod> -- cat /etc/resolv.conf |
| One short name becomes several queries | kubectl exec <pod> -- dig +search +trace payments |
| A trailing dot skips the search list | kubectl exec <pod> -- dig db.corp.example. +noall +stats |
| CoreDNS ships two replicas, whatever the node count | kubectl get deploy coredns -n kube-system |
| Its config is a chain, in order | kubectl get cm coredns -n kube-system -o jsonpath='{.data.Corefile}' |
| NodeLocal runs on every node, or none | kubectl get ds node-local-dns -n kube-system |
| The interface allowance is being hit | ethtool -S eth0 | grep linklocal_allowance_exceeded |