Back to Blog

CoreDNS & Service Discovery for the CKA Exam: Cluster DNS, the Corefile, dnsPolicy & Troubleshooting Name Resolution

A hands-on CKA guide to CoreDNS and Kubernetes service discovery — how in-cluster DNS works, Service and Pod DNS names, the Corefile ConfigMap and its plugins, Pod dnsPolicy and the ndots:5 search-domain trap, headless services and StatefulSet DNS, and a repeatable method for troubleshooting broken name resolution.

By Sailor Team , September 8, 2026

DNS is the plumbing that makes a Kubernetes cluster feel like one machine. Your frontend calls http://orders-api and it just works — because CoreDNS resolves that short name to a Service’s ClusterIP, and kube-proxy load-balances it to a healthy Pod. The CKA exam calls this out explicitly under Services & Networking: “Understand and use CoreDNS.” In practice that means two things — knowing the DNS name for anything in the cluster, and being able to fix name resolution when it breaks, which is a favorite of the 30%-weighted Troubleshooting domain.

This guide takes a hands-on view of CoreDNS and service discovery for the CKA exam. We’ll trace how a lookup actually happens, decode the DNS naming scheme, open up the Corefile, work through dnsPolicy and the infamous ndots:5 search-domain behavior, cover headless-service and StatefulSet DNS, and finish with a repeatable troubleshooting method you can run under exam pressure.

How DNS Works Inside a Cluster

CoreDNS is the cluster’s DNS server. It runs as an ordinary Deployment (two replicas by default) in the kube-system namespace, fronted by a Service named kube-dns (the name is kept for backwards compatibility) with a stable ClusterIP — conventionally the .10 address of the Service CIDR, e.g. 10.96.0.10.

kubectl get deployment coredns -n kube-system
kubectl get pods -n kube-system -l k8s-app=kube-dns
kubectl get svc kube-dns -n kube-system      # note the ClusterIP

When the kubelet starts a Pod, it writes that ClusterIP into the Pod’s /etc/resolv.conf as the nameserver. So every DNS query from a Pod goes to the kube-dns Service, which kube-proxy forwards to a CoreDNS Pod. CoreDNS then answers cluster names itself and forwards everything else (like github.com) to an upstream resolver. Inspect it from inside any Pod:

kubectl exec -it <pod> -- cat /etc/resolv.conf
# nameserver 10.96.0.10
# search <namespace>.svc.cluster.local svc.cluster.local cluster.local
# options ndots:5

Those three lines — nameserver, search, and options ndots — explain almost every DNS behavior on the exam. Hold on to them.

The DNS Naming Scheme

Kubernetes gives predictable DNS names to Services and Pods. Memorize the shapes:

ObjectDNS name (A record)Resolves to
Service<service>.<namespace>.svc.cluster.localthe Service’s ClusterIP
Headless Service<service>.<namespace>.svc.cluster.localthe IPs of all ready Pods
Pod<pod-ip-dashes>.<namespace>.pod.cluster.localthat Pod’s IP (e.g. 10-244-1-5...)
StatefulSet Pod<pod-name>.<service>.<namespace>.svc.cluster.localthat specific Pod’s IP

The full form (ending in cluster.local) is the fully qualified domain name (FQDN). Thanks to the search list in resolv.conf, you rarely type the whole thing:

  • From a Pod in the same namespace, orders-api resolves — the search list appends <namespace>.svc.cluster.local.
  • From a Pod in another namespace, use orders-api.<namespace> (short) or the full orders-api.<namespace>.svc.cluster.local.
  • Cross-namespace with a short name fails — a classic bug. orders-api in namespace web will not find a Service in namespace payments; you need orders-api.payments.

_srv-port-name._protocol.<service>.<namespace>.svc.cluster.local gives you SRV records for named ports, which is how clients discover port numbers for headless services.

The ndots:5 Trap

This is the concept that separates people who understand cluster DNS from people who memorized name shapes. The options ndots:5 line means: if a name has fewer than 5 dots, try it against the search list first before treating it as absolute.

Count the dots in orders-api.payments.svc.cluster.local — that’s 4 dots, which is less than 5. So the resolver first appends each search domain and queries those (mostly non-existent) names, gets NXDOMAIN, and only then tries the name as-is. That’s up to four wasted lookups for a name that was already fully qualified.

The fix — and the reason it matters operationally — is the trailing dot: orders-api.payments.svc.cluster.local. (note the final .) is an absolute FQDN, so the resolver skips the search list entirely and resolves it in one query. Under heavy request rates, the wasted search-list lookups are a real source of DNS load on CoreDNS and latency in your app. Expect a question that asks why external lookups are slow, or why CoreDNS is under load — ndots:5 plus un-terminated names is the answer.

The Corefile: Configuring CoreDNS

CoreDNS is configured by a file called the Corefile, stored in a ConfigMap named coredns in kube-system:

kubectl -n kube-system get configmap coredns -o yaml

A typical Corefile looks like this, and each line is a plugin:

.:53 {
    errors
    health { lameduck 5s }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
        pods insecure
        fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    forward . /etc/resolv.conf { max_concurrent 1000 }
    cache 30
    loop
    reload
    loadbalance
}

The plugins you should recognize for the exam:

PluginWhat it does
kubernetesAnswers cluster names (*.cluster.local) by watching the API for Services/Pods/Endpoints — this is what makes service discovery work
forwardSends non-cluster queries (e.g. google.com) to an upstream resolver — here, the node’s /etc/resolv.conf
cacheCaches answers (30s) to cut load and latency
reloadAutomatically reloads the Corefile a short time after the ConfigMap changes — no manual restart needed
errors / logLog errors (add log to log every query when debugging)
health / readyLiveness/readiness endpoints for the CoreDNS Pods
hosts / rewriteAdd static records or rewrite queries — used for stub domains and custom entries

To customize CoreDNS — say, forward a private domain to an on-prem DNS server, or add a static host entry — you edit the ConfigMap:

kubectl -n kube-system edit configmap coredns
# then, if you want to force it immediately:
kubectl -n kube-system rollout restart deployment coredns

The reload plugin usually picks up changes within a minute or two; a rollout restart applies them instantly. Adding a stub domain, for example, is a matter of a small extra server block that forwards a specific zone:

consul.local:53 {
    errors
    cache 30
    forward . 10.150.0.1
}

Pod DNS: dnsPolicy and dnsConfig

Each Pod chooses how its DNS is set up via dnsPolicy. Know these four values:

dnsPolicyBehavior
ClusterFirstDefault. Cluster names go to CoreDNS; everything else is forwarded upstream
ClusterFirstWithHostNetWhat you need for hostNetwork: true Pods that should still use cluster DNS
DefaultThe Pod inherits the node’s /etc/resolv.conf — it does not use cluster DNS
NoneIgnore everything; you must supply DNS settings via dnsConfig

A subtle, testable gotcha: a Pod with hostNetwork: true and the default ClusterFirst will actually fall back to the node’s resolver and lose cluster DNS. If such a Pod needs to resolve Service names, set dnsPolicy: ClusterFirstWithHostNet.

dnsConfig lets you fine-tune resolution — add extra nameservers, search domains, or change ndots:

spec:
  dnsPolicy: "None"
  dnsConfig:
    nameservers: ["10.96.0.10"]
    searches: ["svc.cluster.local", "example.com"]
    options:
      - name: ndots
        value: "2"

Lowering ndots is a legitimate way to reduce the search-list overhead described above for latency-sensitive workloads.

Headless Services and StatefulSet DNS

A headless Service (clusterIP: None) has no virtual IP. Instead, its DNS name resolves to the A records of every ready Pod behind it. This is how clients that need to talk to individual Pods — databases, message brokers, anything that isn’t stateless-and-interchangeable — do discovery.

Combine a headless Service with a StatefulSet and each Pod gets a stable, predictable DNS name that survives rescheduling:

web-0.nginx.default.svc.cluster.local
web-1.nginx.default.svc.cluster.local
web-2.nginx.default.svc.cluster.local

That stability is the whole point of StatefulSets: web-0 is always reachable at the same name, so peers can form a cluster (think etcd, Kafka, Cassandra). The StatefulSet’s serviceName field must reference the headless Service that governs these names. NetworkPolicy and DNS interplay is worth reviewing alongside the CKA NetworkPolicy guide, and the broader Services picture is covered in the CKA networking deep dive.

Troubleshooting DNS: A Repeatable Method

Broken name resolution is one of the most common Troubleshooting-domain scenarios. Work it top-down; don’t guess.

1. Reproduce from a debug Pod. Use busybox:1.28 specifically — later BusyBox images ship a buggy nslookup:

kubectl run -it --rm dnstest --image=busybox:1.28 --restart=Never -- sh
# inside:
nslookup kubernetes.default          # should return the API Service ClusterIP
nslookup orders-api.payments         # your target Service
cat /etc/resolv.conf                  # nameserver / search / ndots correct?

If kubernetes.default resolves but your Service doesn’t, DNS is healthy and the problem is your Service or its Endpoints — check that the Service exists and its selector matches Pods (kubectl get endpoints <svc>; empty endpoints = no matching/ready Pods).

2. Check CoreDNS itself. If nothing resolves:

kubectl get pods -n kube-system -l k8s-app=kube-dns      # Running & Ready?
kubectl logs -n kube-system -l k8s-app=kube-dns          # errors, crash loops?
kubectl get svc kube-dns -n kube-system                  # ClusterIP present?
kubectl get endpoints kube-dns -n kube-system            # backing CoreDNS Pods listed?

CoreDNS Pods CrashLoopBackOff with a plugin/loop message means a forwarding loop — usually the node’s /etc/resolv.conf points back at a local stub (127.0.0.53 from systemd-resolved). That’s a known trap.

3. Check the Corefile. A malformed coredns ConfigMap breaks resolution cluster-wide. Diff it against a known-good Corefile; confirm the kubernetes and forward plugins are intact.

4. Check NetworkPolicy. This one bites people: a default-deny egress policy in a namespace silently blocks DNS, because Pods can no longer reach kube-dns on port 53 (UDP and TCP). Every symptom looks like “DNS is down” but CoreDNS is fine. The fix is an egress rule allowing traffic to the kube-dns Pods on port 53:

egress:
  - to:
      - namespaceSelector: {}
        podSelector:
          matchLabels: { k8s-app: kube-dns }
    ports:
      - { protocol: UDP, port: 53 }
      - { protocol: TCP, port: 53 }

Working DNS problems methodically — Pod resolver → Service/Endpoints → CoreDNS → Corefile → NetworkPolicy — is exactly the discipline the CKA troubleshooting guide drills.

Common Exam Tasks and Traps

  • Cross-namespace short names fail. Use service.namespace or the FQDN. service alone only works within the same namespace.
  • Empty Endpoints = broken selector, not broken DNS. If kubernetes.default resolves, CoreDNS is healthy.
  • hostNetwork: true + ClusterFirst loses cluster DNS → use ClusterFirstWithHostNet.
  • NetworkPolicy default-deny egress blocks port 53 → resolution dies until you allow egress to kube-dns.
  • ndots:5 causes extra search-list lookups; a trailing dot makes a name absolute and faster.
  • Edit the coredns ConfigMap to customize; the reload plugin applies it, or rollout restart deployment coredns.
  • Use busybox:1.28 for nslookup — newer tags are buggy.
  • Headless Service returns Pod IPs; StatefulSet + headless Service gives stable per-Pod names.

Practice DNS in a Real Cluster

CoreDNS questions reward muscle memory: knowing the FQDN pattern without thinking, and running the resolver → Endpoints → CoreDNS → NetworkPolicy checklist fast. Because the CKA is entirely hands-on, reading about DNS isn’t enough — you need to break and fix it in a live cluster. The Certified Kubernetes Administrator (CKA) Mock Exam Bundle gives you five full-length, performance-based mock exams (two hours each) in a real terminal against an actual Kubernetes cluster — the same format as exam day — with DNS and service-discovery scenarios among 100+ tasks. Pair it with the 30-day CKA study plan to sequence networking alongside the rest of the syllabus, and check the CKA exam domains breakdown to see how Services & Networking and Troubleshooting stack up.

Frequently Asked Questions

What is the DNS name of a Kubernetes Service?

A Service’s fully qualified name is <service>.<namespace>.svc.cluster.local, which resolves to its ClusterIP. Within the same namespace you can use just <service>; from another namespace use <service>.<namespace>. The svc.cluster.local suffix comes from the Pod’s DNS search list.

Where does CoreDNS run and how do Pods reach it?

CoreDNS runs as a Deployment in the kube-system namespace, fronted by a Service named kube-dns with a fixed ClusterIP (often 10.96.0.10). The kubelet writes that ClusterIP into every Pod’s /etc/resolv.conf, so all Pod DNS queries go to the kube-dns Service and are forwarded to a CoreDNS Pod.

What does ndots:5 mean and why does it matter?

ndots:5 tells the resolver that any name with fewer than 5 dots should be tried against the search-domain list before being treated as absolute. Fully qualified cluster names have only 4 dots, so they trigger several wasted search-list lookups. Appending a trailing dot (svc.name.ns.svc.cluster.local.) marks the name absolute and skips those extra queries — reducing CoreDNS load and DNS latency.

How do I configure or customize CoreDNS?

Edit the coredns ConfigMap in kube-system (kubectl -n kube-system edit configmap coredns). The Corefile inside it is a list of plugins; add a forward block for a stub domain, a hosts entry for static records, or a rewrite rule as needed. The reload plugin applies changes within a minute or two, or run kubectl -n kube-system rollout restart deployment coredns to apply immediately.

Why is DNS failing only in one namespace?

The most common cause is a NetworkPolicy with default-deny egress in that namespace, which blocks Pods from reaching kube-dns on UDP/TCP port 53. CoreDNS is healthy, but the Pods can’t reach it. Add an egress rule allowing traffic to the kube-dns Pods on port 53 to restore resolution.

How do I troubleshoot a DNS problem on the CKA?

Run a busybox:1.28 debug Pod and nslookup kubernetes.default. If that resolves, CoreDNS works — check your Service’s Endpoints and selector. If nothing resolves, check the CoreDNS Pods and logs (-l k8s-app=kube-dns), the kube-dns Service/Endpoints, the coredns ConfigMap for a malformed Corefile, and any NetworkPolicy blocking port 53.

What DNS name does a StatefulSet Pod get?

With a governing headless Service, each StatefulSet Pod gets a stable name <pod-name>.<service>.<namespace>.svc.cluster.local — for example web-0.nginx.default.svc.cluster.local. The name persists across rescheduling, which is why StatefulSets are used for clustered stateful apps that need to address peers individually.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now