DNS Basics
This page is a hands-on intro to Kubernetes DNS: how names like service.namespace.svc.cluster.local resolve, what records CoreDNS serves, and how to test resolution from inside a pod.
Prerequisites
- A running cluster on Kubernetes 1.36.2 with CoreDNS installed (the default cluster DNS).
kubectlconfigured against the cluster.- A debug image with DNS tools.
nicolaka/netshootbundlesdig,nslookup, andnc.
Quick one-off debug pod:
kubectl run tmp --rm -it --image=nicolaka/netshoot --restart=Never -- bashBasic Examples
1. Resolve a Service by short name
Inside the same namespace, the Service name alone is enough.
dig +short payments- The pod's
resolv.confsearchlist appendsnamespace.svc.cluster.local. - So
paymentsexpands topayments.<namespace>.svc.cluster.local. - The answer is the Service's stable ClusterIP.
- This only works from a pod in the same namespace as the Service.
2. Resolve across namespaces
Add the namespace label to reach a Service elsewhere.
dig +short payments.billingpayments.billingexpands via thesvc.cluster.localsuffix in the search list.- Use this form whenever caller and callee live in different namespaces.
- No NetworkPolicy is bypassed; DNS resolution and traffic policy are separate concerns.
3. Use the fully qualified name
The absolute FQDN skips the search-list guesswork.
dig +short payments.billing.svc.cluster.local- The trailing zone
svc.cluster.localmarks this as a Service A record. - FQDNs avoid extra failed lookups from the
ndots:5search behavior. - Prefer FQDNs in config files shared across namespaces or languages.
4. Inspect a pod's resolver config
See exactly what the kubelet injected.
kubectl exec tmp -- cat /etc/resolv.confsearch myns.svc.cluster.local svc.cluster.local cluster.local
nameserver 10.96.0.10
options ndots:5nameserveris the cluster DNS Service ClusterIP (often10.96.0.10).- The
searchdomains enable short-name resolution. ndots:5means names with fewer than 5 dots try the search list first.
5. Look up the DNS Service itself
CoreDNS sits behind a Service named kube-dns.
kubectl -n kube-system get svc kube-dns- The Service is named
kube-dnsfor backward compatibility even though CoreDNS serves it. - Its ClusterIP matches the
nameserverin every pod'sresolv.conf. - The backing pods are the CoreDNS Deployment in
kube-system.
6. Resolve a Pod's SRV record for a named port
Services publish SRV records for named ports.
dig +short SRV _http._tcp.payments.billing.svc.cluster.local- The format is
_port-name._protocol.service.namespace.svc.cluster.local. - SRV records return the port number and target hostname.
- Clients that support SRV can discover ports without hardcoding them.
7. Resolve an external name
CoreDNS forwards names it does not own to upstream resolvers.
dig +short api.github.com- Names outside
cluster.localare forwarded via CoreDNS'sforwardplugin. - By default the upstream is the node's
/etc/resolv.conf. - This is how in-cluster pods reach the public internet by name.
Intermediate Examples
8. Distinguish ClusterIP from headless resolution
Headless Services return pod IPs instead of one virtual IP.
apiVersion: v1
kind: Service
metadata:
name: cassandra
namespace: data
spec:
clusterIP: None
selector:
app: cassandra
ports:
- port: 9042dig +short cassandra.data.svc.cluster.localclusterIP: Nonemakes this a headless Service.- The lookup returns one A record per Ready pod, not a single ClusterIP.
- StatefulSets use this to give each pod a stable name like
cassandra-0.cassandra.data.svc.cluster.local.
9. Tune ndots to reduce lookup overhead
High ndots can cause several failed lookups for external names.
apiVersion: v1
kind: Pod
metadata:
name: web
spec:
dnsConfig:
options:
- name: ndots
value: "2"
containers:
- name: web
image: registry.example.com/web:1.4.0@sha256:abc123- Lowering
ndotsmakes external FQDNs resolve on the first try. - Set
dnsConfigper pod or use a fully qualified name with a trailing dot. - Do not lower it so far that in-namespace short names stop working.
10. Point a pod at custom resolvers
dnsPolicy: None gives you full control of resolv.conf.
spec:
dnsPolicy: None
dnsConfig:
nameservers:
- 10.96.0.10
searches:
- myns.svc.cluster.local
- svc.cluster.local
options:
- name: ndots
value: "5"dnsPolicy: Noneignores cluster defaults and uses only yourdnsConfig.- Useful for pods that must query a specific DNS setup.
- Keep the cluster DNS ClusterIP in
nameserversif the pod still needs Service resolution.
11. Allow DNS under a default-deny NetworkPolicy
A default-deny egress policy blocks DNS unless you allow port 53.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: myns
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53- Name resolution and traffic policy are independent; a deny-all egress rule silently breaks DNS.
- This policy permits egress to the
kube-systemnamespace where CoreDNS runs. - Allow both UDP and TCP on port 53, since large answers fall back to TCP.
- Apply this before tightening egress so pods can still resolve Service names.
12. Compare nslookup and dig output
Use nslookup when a container lacks dig.
kubectl exec tmp -- nslookup payments.billing.svc.cluster.localServer: 10.96.0.10
Address: 10.96.0.10#53
Name: payments.billing.svc.cluster.local
Address: 10.104.12.7Serverconfirms the cluster DNS ClusterIP is answering.- The returned
Addressis the Service ClusterIP for a normal Service. - If you get
NXDOMAIN, check the namespace label and that the Service exists.
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).