Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Cluster DNS with CoreDNS

By Kokil Thapa | Last reviewed: September 2026

Every pod in a Kubernetes cluster needs a reliable way to turn api.default.svc.cluster.local into an IP address. That job belongs to cluster DNS with CoreDNS, the default in-cluster resolver since Kubernetes 1.13. When DNS breaks, microservices cannot talk, health checks fail, and deployments look fine on paper but stall in production. This guide walks through how CoreDNS fits the cluster, how to deploy and tune it, and how to fix the failures I have seen on real client infrastructure. If you are new to name resolution itself, start with our practical guide to how DNS works before diving into cluster internals.

What is cluster DNS with CoreDNS in Kubernetes?

CoreDNS is a flexible, plugin-driven DNS server written in Go. In Kubernetes it replaces the older kube-dns stack. The control plane still stores service and endpoint data in etcd. CoreDNS watches the API and builds records on the fly.

A typical query path looks like this. A pod asks its local resolver at 10.96.0.10 (the cluster IP of the kube-dns Service). CoreDNS receives the query, matches a zone in the Corefile, and returns an A record, a CNAME, or an NXDOMAIN.

Cluster DNS with CoreDNS — Query FlowApp Podresolv.confkube-dns SvcClusterIPCoreDNS PodsDeploymentKubernetes APIServices + EndpointsUpstream DNSNode resolversInternal zones from API · External names forwarded upstream
Cluster DNS with CoreDNS resolves in-cluster service names via the API and forwards everything else to upstream resolvers.

Two DNS names matter for every workload. Short names like mysql resolve inside the same namespace. Fully qualified names like mysql.database.svc.cluster.local work across namespaces. The cluster domain defaults to cluster.local. You can change it, but most managed platforms keep the default.

CoreDNS also supports pod-level DNS records when the pod plugin is enabled. That gives you addresses like 10-244-1-5.default.pod.cluster.local. Many teams disable this for smaller zone files and faster lookups. For background on record types, see our post on DNS record types explained.

Core components you should know

  • Corefile — ConfigMap in kube-system that defines zones and plugins.
  • coredns Deployment — Usually two or more replicas for HA.
  • kube-dns Service — Stable ClusterIP every pod uses via /etc/resolv.conf.
  • NodeLocal DNSCache — Optional daemonset that caches on each node (common on large clusters).

The relationship between CoreDNS and etcd is indirect. CoreDNS never reads etcd directly. It uses the Kubernetes API, which is backed by etcd as described in our etcd in Kubernetes guide. That separation keeps DNS logic in one place and cluster state in another.

How do you deploy CoreDNS in a Kubernetes cluster?

Managed clusters on GKE, EKS, and AKS ship CoreDNS by default. Self-managed clusters on Ubuntu need explicit installation. The steps below work on kubeadm-style setups running Kubernetes 1.28 or later.

  1. Confirm no legacy kube-dns pods remain: kubectl get pods -n kube-system -l k8s-app=kube-dns.
  2. Apply the upstream manifest or your distro package: kubectl apply -f https://github.com/coredns/deployment/raw/master/kubernetes/coredns.yaml.sed (adjust for your cluster CIDR).
  3. Verify the Deployment: kubectl -n kube-system get deploy coredns.
  4. Check the ConfigMap: kubectl -n kube-system get configmap coredns -o yaml.
  5. Run a test pod and resolve a Service: kubectl run -it --rm dns-test --image=busybox:1.36 --restart=Never -- nslookup kubernetes.default.

On bare-metal Ubuntu nodes I maintain for clients, I align node resolvers first. Broken upstream DNS on the host breaks CoreDNS forwarding. Our Ubuntu DNS configuration guide covers systemd-resolved and /etc/resolv.conf pitfalls that propagate into pods.

Default Corefile for a standard cluster

Most clusters start with a Corefile like this. Edit the ConfigMap, then roll the Deployment.

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

Each block is a server block listening on port 53. The kubernetes plugin watches Services and Endpoints. The forward plugin sends external queries to the node's /etc/resolv.conf inside the CoreDNS pod. After editing, restart pods or rely on the reload plugin for a graceful reload.

kubectl -n kube-system rollout restart deployment/coredns
kubectl -n kube-system rollout status deployment/coredns

For multi-cluster GitOps workflows, pin the CoreDNS manifest in Git and sync with Argo CD. Patterns for that appear in our multi-cluster Kubernetes across clouds article. Treat DNS config like any other cluster baseline.

CoreDNS Deployment ArchitectureConfigMapCorefile + zonescoredns Deployment2+ replicas, anti-affinitykube-dns ServiceClusterIP :53RBAClist/watch ServicesPod DNS PolicyClusterFirst · ndots:5 · search pathsRBAC must allow CoreDNS to watch API resources — see kubernetes RBAC guide
Deploy cluster DNS with CoreDNS as a ConfigMap-backed Deployment fronted by the kube-dns ClusterIP Service.

CoreDNS needs RBAC to list and watch Services, Endpoints, and Namespaces. Restricting those permissions breaks resolution silently. Our Kubernetes RBAC guide explains how to audit ServiceAccount bindings without over-tightening system components.

How does CoreDNS resolve service names inside a cluster?

Resolution follows predictable search-path rules. When a pod queries api, the stub resolver tries suffixes from dnsConfig or the default search list. With ndots:5, names with fewer than five dots get search domains appended first.

The default search path looks like this:

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5

CoreDNS receives api.default.svc.cluster.local after search expansion. The kubernetes plugin matches the zone cluster.local. It returns the ClusterIP for a ClusterIP Service. For headless Services it returns pod IPs from Endpoints or EndpointSlices.

Headless vs ClusterIP behaviour

A ClusterIP Service gets one stable virtual IP. DNS returns that IP regardless of which pods are ready. A headless Service (clusterIP: None) returns A records for each ready endpoint. StatefulSets depend on this for stable network identity per pod.

ExternalName Services return CNAME records pointing outside the cluster. That is useful for aliasing managed databases without hard-coding IPs. Cross-cloud setups often combine this with external DNS as covered in our cross-cloud DNS and traffic routing post.

CoreDNS exposes Prometheus metrics on port 9153 when the prometheus plugin is enabled. Watch coredns_dns_requests_total and coredns_forward_healthcheck_broken_total for early warning signs. A spike in NXDOMAIN often means a mis-typed Service name or a namespace mismatch.

CoreDNS vs kube-dns: which should you use in 2026?

kube-dns is deprecated. No new clusters should run it. CoreDNS is the only supported in-cluster DNS for current Kubernetes releases. If you still run kube-dns on an older cluster, plan migration before your control plane upgrade forces it.

CriteriaCoreDNSkube-dns (legacy)
ArchitectureSingle binary, plugin chain in Corefilednsmasq sidecar + kubedns container
Config modelCorefile zones, hot reloadConfigMap with limited knobs
ObservabilityNative Prometheus pluginRequires sidecar scraping
Custom zonesfile, rewrite, template pluginsHarder to extend cleanly
Kubernetes supportDefault since 1.13, required on modern versionsRemoved from current docs
Performance tuningcache, loadbalance, NodeLocal DNSCachednsmasq cache only

The verdict is straightforward. Use CoreDNS everywhere. Migrate legacy kube-dns during your next maintenance window. The official Kubernetes documentation at kubernetes.io/docs/concepts/services-networking/dns-pod-service/ describes current behaviour and naming conventions.

For teams comparing in-cluster DNS with a standalone BIND server, the trade-off is scope. BIND excels at authoritative zones for public domains. CoreDNS excels at dynamic Kubernetes service discovery. Many production stacks run both layers. Our BIND DNS server on Linux guide covers the authoritative side when you need it.

CoreDNS vs kube-dns — ArchitectureCoreDNS (current default)Corefile plugin chainkubernetes · forward · cacheSingle container per podLower overhead · easier opskube-dns (legacy)kubedns + dnsmasq sidecarTwo containers · harder tuningDeprecated pathMigrate before upgrade2026 recommendation: CoreDNS onlyNodeLocal DNSCache optional at scale
CoreDNS replaces the two-container kube-dns stack with a single configurable DNS server for cluster DNS.

How do you configure custom DNS zones with CoreDNS?

Production apps often need stub zones for internal domains, split-horizon forwarding, or ad-block style rewrites. CoreDNS handles this with extra server blocks in the Corefile.

Forward an internal domain to corporate DNS

Suppose your company uses corp.example.com on-premises. Add a block that forwards only that suffix:

corp.example.com:53 {
    errors
    cache 30
    forward . 10.10.0.53 10.10.0.54
}

Keep the default .:53 block for cluster.local and upstream internet resolution. Order matters when zones overlap. More specific zones should appear as separate server blocks.

Override a hostname with the hosts plugin

hosts /etc/coredns/hosts.db {
    fallthrough
}

Mount the hosts file via a ConfigMap volume. This is handy for pinning legacy dependencies during migration. Prefer Kubernetes Services once the dependency runs inside the cluster.

Custom dnsConfig on a Pod

Some workloads need different upstreams or search paths. Set dnsPolicy: None and define dnsConfig explicitly:

apiVersion: v1
kind: Pod
metadata:
  name: custom-dns-pod
spec:
  dnsPolicy: None
  dnsConfig:
    nameservers:
      - 10.96.0.10
    searches:
      - myapp.svc.cluster.local
      - svc.cluster.local
    options:
      - name: ndots
        value: "2"
  containers:
    - name: app
      image: myapp:1.0

Lowering ndots reduces unnecessary search-path queries. That cuts latency for external API calls. Validate with kubectl exec and cat /etc/resolv.conf before rolling to production.

On booking platforms like Adventure Third Pole Trek, microservices call payment and SMS APIs by public hostname. Correct forward rules prevent those calls from looping inside the cluster. Test external resolution from a debug pod after every Corefile change.

How do you troubleshoot CoreDNS when cluster DNS fails?

DNS failures show up as connection timeouts, not always as clear DNS errors. Application logs say "connection refused" or "no such host" while the Service and pods look healthy. Work through the checklist below before restarting random components.

  1. Check CoreDNS pod health: kubectl -n kube-system get pods -l k8s-app=kube-dns — labels still say kube-dns even though the workload is CoreDNS.
  2. Review logs: kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100. Look for loop detection, permission denied, or forward timeouts.
  3. Test from a debug pod: kubectl run -it --rm debug --image=nicolaka/netshoot --restart=Never -- dig @10.96.0.10 kubernetes.default.svc.cluster.local.
  4. Verify kube-dns Service endpoints match running CoreDNS pods.
  5. Confirm node upstream DNS works on the host with dig google.com before blaming CoreDNS.
  6. Check for CoreDNS loop: the loop plugin detects when forwarded queries return to CoreDNS. Fix by pointing forward at real upstreams, not 127.0.0.1.

A common mistake on Ubuntu nodes: /etc/resolv.conf points to 127.0.0.53 (systemd-resolved). CoreDNS pods inherit that and create a loop or timeout. Set node-level resolvers to real upstream IPs, or use the forward plugin with explicit IPs instead of /etc/resolv.conf.

CoreDNS Troubleshooting FlowDNS lookup failing?Internal name?External name?Check ServiceEndpoints · namespaceCheck forwardNode resolvers · loopFix Corefile · restartValidate with dig from netshoot
Troubleshoot cluster DNS with CoreDNS by splitting internal service failures from external forward and loop issues.

Scale-related problems need horizontal fixes. Increase CoreDNS replicas when CPU throttling appears. Add Pod anti-affinity so replicas land on different nodes. For clusters above roughly 200 nodes, deploy NodeLocal DNSCache to cut cross-node traffic to the kube-dns Service.

When you manage many clusters through Rancher or similar tools, DNS baselines drift fast. Standardise the Corefile template across environments. Our Rancher multi-cluster management guide covers fleet-wide config patterns that apply here.

If you need regex testing for rewrite rules before applying them, the regex tester tool on this site helps validate patterns offline. CoreDNS rewrite mistakes are easier to catch before they hit production.

For deeper CoreDNS plugin reference, the project documentation at coredns.io/plugins/ is the authoritative source. The CNCF project page at cncf.io/projects/coredns tracks release cadence and governance.

Key Takeaways

  • Cluster DNS with CoreDNS is the default Kubernetes resolver—plan every deployment around a healthy Corefile and at least two replicas.
  • Internal names resolve through the kubernetes plugin; external names depend on correct forward upstreams on your nodes.
  • Migrate legacy kube-dns before upgrading Kubernetes; CoreDNS is the only supported path in 2026.
  • Fix Ubuntu/systemd-resolved loop issues by pointing forward at real upstream IPs, not 127.0.0.53.
  • Use Prometheus metrics and dig from a netshoot pod to separate Service misconfig from DNS infrastructure failure.
  • Pin CoreDNS manifests in Git for multi-cluster fleets so DNS config does not drift silently.

People Also Ask

What IP address do pods use for DNS in Kubernetes?

Pods send queries to the ClusterIP of the kube-dns Service in kube-system. That IP appears as the nameserver in /etc/resolv.conf. It is typically something like 10.96.0.10, but the exact address depends on your Service CIDR. Run kubectl get svc kube-dns -n kube-system to confirm.

Can you run CoreDNS outside Kubernetes?

Yes. CoreDNS is a general-purpose DNS server. Many teams run it on bare metal or at the edge. Inside Kubernetes it adds the kubernetes plugin for automatic service record generation. Outside the cluster you would use file, etcd, or other plugins instead.

Why do I get NXDOMAIN for a service that exists?

Most often the query uses the wrong namespace or an incomplete search path. A pod in staging asking for api resolves api.staging.svc.cluster.local, not api.production.svc.cluster.local. Use the fully qualified name to test, then fix the Service name or namespace in application config.

Does CoreDNS work with IPv6 clusters?

Yes. Enable the ip6.arpa reverse zone in the Corefile alongside in-addr.arpa for IPv4. Dual-stack clusters need dual-stack Services and EndpointSlices. Verify AAAA records with dig AAAA from a debug pod before declaring IPv6 ready.

Build reliable cluster DNS from day one

Cluster DNS with CoreDNS is easy to ignore until it breaks a release. Treat the Corefile, node resolvers, and RBAC as first-class infrastructure. Test resolution after every platform upgrade and every network change. If you are standing up Kubernetes for a new product—or fixing DNS on an existing fleet—Linux system administration support and our ongoing maintenance services cover deployment, tuning, and incident response. For greenfield application work on top of a solid cluster, see enterprise application development. Ready to talk through your setup? Contact us with your cluster size and distro—we will map a practical DNS baseline you can ship this week.

Frequently Asked Questions

Cluster DNS with CoreDNS is the in-cluster DNS server that resolves Kubernetes service and pod names. It runs as a Deployment in kube-system, reads zone rules from a Corefile ConfigMap, and forwards external queries to upstream resolvers on your nodes.

Pods query the ClusterIP of the kube-dns Service in kube-system, shown as the nameserver in /etc/resolv.conf. It is often 10.96.0.10, but the exact IP depends on your Service CIDR. Confirm with kubectl get svc kube-dns -n kube-system.

Use CoreDNS everywhere. kube-dns is deprecated and removed from current Kubernetes docs; CoreDNS has been the default since Kubernetes 1.13 and is the only supported in-cluster DNS on modern clusters.

Managed GKE, EKS, and AKS clusters ship CoreDNS by default. On kubeadm-style setups running Kubernetes 1.28 or later, confirm no legacy kube-dns pods remain with kubectl get pods -n kube-system -l k8s-app=kube-dns. Apply the upstream manifest, verify the coredns Deployment and Corefile ConfigMap in kube-system, then test from a busybox pod with nslookup kubernetes.default. On bare-metal Ubuntu nodes I maintain, I align node upstream resolvers first because broken host DNS breaks CoreDNS forwarding into pods.

A pod sends queries to the kube-dns ClusterIP. The stub resolver expands short names using search domains like default.svc.cluster.local, svc.cluster.local, and cluster.local with ndots:5. CoreDNS matches the cluster.local zone via the kubernetes plugin, which watches the Kubernetes API for Services and Endpoints. ClusterIP Services return one stable virtual IP. Headless Services return A records for each ready endpoint. ExternalName Services return CNAME records pointing outside the cluster.

The Corefile is a ConfigMap in kube-system that defines server blocks, zones, and plugins such as kubernetes, forward, cache, loop, and reload. Most clusters start with a .:53 block that handles cluster.local, forwards external queries to /etc/resolv.conf inside the CoreDNS pod, and exposes Prometheus metrics on port 9153. After editing the ConfigMap, restart the Deployment with kubectl rollout restart or rely on the reload plugin for a graceful reload. Pin the manifest in Git and sync with Argo CD so DNS config does not drift across clusters.

Add separate server blocks in the Corefile for each zone. To forward an internal domain like corp.example.com to corporate DNS, create a corp.example.com:53 block with forward pointing at your on-premises resolvers, while keeping the default .:53 block for cluster.local and internet resolution. More specific zones should be separate blocks when suffixes overlap. For temporary hostname overrides, use the hosts plugin with a file mounted from a ConfigMap. Prefer Kubernetes Services once dependencies run inside the cluster. Workloads needing different upstreams can set dnsPolicy: None and define dnsConfig with custom nameservers, searches, and a lower ndots value.

Most often the query targets the wrong namespace or an incomplete search path. A pod in staging asking for api resolves api.staging.svc.cluster.local, not api.production.svc.cluster.local. Test with the fully qualified name like mysql.database.svc.cluster.local, then fix the Service name or namespace in application config. A spike in NXDOMAIN in Prometheus metrics often means a mis-typed Service name rather than a CoreDNS outage.

DNS failures often appear as connection timeouts or "no such host" errors while Services look healthy. Check CoreDNS pod health with kubectl get pods -n kube-system -l k8s-app=kube-dns, review logs for loop detection or permission errors, and test with dig from a netshoot pod against the kube-dns ClusterIP. Verify Service endpoints match running CoreDNS pods and confirm node upstream DNS works on the host before blaming CoreDNS. Split internal service failures from external forward and loop issues. Increase replicas if CPU throttling appears, add pod anti-affinity across nodes, and standardise Corefile templates when managing many clusters through Rancher or similar fleet tools.

The loop plugin fires when forwarded queries circle back to CoreDNS instead of reaching real upstream resolvers. A common mistake on Ubuntu nodes is /etc/resolv.conf pointing to 127.0.0.53 via systemd-resolved. CoreDNS pods inherit that path through the forward plugin using /etc/resolv.conf and either loop or timeout. Fix it by setting node-level resolvers to real upstream IPs, or configure the forward plugin with explicit upstream addresses instead of /etc/resolv.conf. Test external resolution from a debug pod after every Corefile change.

NodeLocal DNSCache is an optional DaemonSet that caches DNS on each node and is common on large clusters. Deploy it when you have roughly 200 or more nodes and see cross-node traffic to the kube-dns Service becoming a bottleneck. It complements CoreDNS rather than replacing it. For smaller clusters, running at least two CoreDNS replicas with pod anti-affinity on different nodes is usually enough for high availability without adding node-local caching overhead.

Yes. CoreDNS is a general-purpose DNS server written in Go. Outside Kubernetes you use file, etcd, or other plugins instead of the kubernetes plugin for automatic service record generation.

CoreDNS needs RBAC to list and watch Services, Endpoints, and Namespaces through the Kubernetes API. It never reads etcd directly; the API server mediates access to cluster state. Restricting those ServiceAccount permissions breaks resolution silently without obvious pod crashes. Audit bindings carefully during security hardening and avoid over-tightening permissions on system components in kube-system.

A ClusterIP Service gets one stable virtual IP, and DNS returns that IP regardless of which backend pods are ready. A headless Service with clusterIP: None returns A records for each ready endpoint IP instead of a single ClusterIP. StatefulSets depend on headless Services for stable per-pod network identity. ExternalName Services return CNAME records pointing outside the cluster, useful for aliasing managed databases without hard-coding IPs in application config.

Yes. Enable the ip6.arpa reverse zone in the Corefile alongside in-addr.arpa for IPv4 reverse lookups. Dual-stack clusters need dual-stack Services and endpoint configuration so the kubernetes plugin can publish correct A and AAAA records. The same Corefile structure with the kubernetes, forward, and cache plugins applies; verify resolution from a debug pod using both address families after enabling IPv6 on the cluster network.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: