CoreDNS Configuration
Summary
- CoreDNS is the default cluster DNS server, configured through a Corefile stored in a ConfigMap.
- Insight: The Corefile is an ordered plugin chain per zone; the order of plugins matters.
- Key Concepts: Corefile, the
kubernetesplugin,forwardfor upstreams, stub domains, andcache. - When to Use: Edit CoreDNS to add upstream forwards, route a private domain to an internal resolver, or tune caching and logging.
- Limitations: A bad Corefile can break cluster-wide resolution, so validate and roll out carefully.
Recipe
Edit the CoreDNS ConfigMap, add or change a plugin block, and let CoreDNS reload.
kubectl -n kube-system edit configmap corednskubectl -n kube-system rollout restart deployment corednsThe default Corefile enables reload, so it picks up ConfigMap changes within a couple of minutes without a restart.
Working Example
Here is a complete Corefile that serves cluster names, adds a stub domain for an internal zone, and forwards everything else to a specific upstream.
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.: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 . 10.0.0.53 {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}
internal.example.com:53 {
errors
cache 30
forward . 10.10.0.10 10.10.0.11
}The first server block handles the root zone ., including cluster.local.
The second block is a stub domain: queries for internal.example.com go to the corporate resolvers at 10.10.0.10 and 10.10.0.11.
Apply it and restart:
kubectl -n kube-system apply -f coredns-configmap.yaml
kubectl -n kube-system rollout restart deployment corednsDeep Dive
The kubernetes plugin
The kubernetes cluster.local in-addr.arpa ip6.arpa line makes CoreDNS authoritative for the cluster zone and reverse zones.
It watches the API server for Services and EndpointSlices and answers A, AAAA, SRV, and PTR queries from that live data.
ttl 30 sets the record TTL; lower values reduce client cache staleness at the cost of more queries.
pods insecure controls pod A records; insecure returns a record without verifying the pod exists, which is the historical default and generally fine.
fallthrough passes unmatched reverse queries to the next plugin instead of returning NXDOMAIN.
Forwarding and stub domains
The forward . 10.0.0.53 plugin sends any name CoreDNS is not authoritative for to the listed upstream.
Using an explicit upstream IP is more predictable than the older /etc/resolv.conf default, which inherits the node resolver.
A stub domain is a separate server block for a specific zone, so internal.example.com is resolved by your chosen resolvers rather than the general upstream.
This is the correct way to reach private DNS zones from inside the cluster.
Cache, reload, and health
cache 30 caches positive and negative answers for up to 30 seconds, cutting load on upstreams and the API server.
reload watches the Corefile and applies changes without a pod restart.
health and ready back the liveness and readiness probes so a broken CoreDNS pod is caught.
loop detects forwarding loops at startup and stops CoreDNS from crashing endlessly.
Gotchas
Editing the wrong plugin order breaks resolution.
Plugins run in a fixed internal order for many, but forward, cache, and kubernetes interactions matter; keep cache after kubernetes and forward.
A forwarding loop crashes CoreDNS.
If your upstream points back at CoreDNS (common when forward . /etc/resolv.conf and the node uses the cluster DNS), the loop plugin will detect it and CoreDNS will refuse to start.
Scaling CoreDNS too low causes latency under load.
DNS-heavy workloads can saturate a two-replica Deployment; scale replicas or deploy NodeLocal DNSCache.
ConfigMap typos silently fail.
Watch CoreDNS logs after an edit; a malformed Corefile keeps the old config running while new pods fail readiness.
kubectl -n kube-system logs -l k8s-app=kube-dnsAlternatives
NodeLocal DNSCache runs a per-node caching agent so pods hit a local cache before CoreDNS, cutting latency and conntrack pressure; pair it with CoreDNS rather than replacing it.
External-dns is not a resolver; it syncs Service and Ingress names to an external DNS provider for outside-the-cluster resolution.
A managed cloud DNS integration can serve private zones, but stub domains in CoreDNS keep resolution logic inside the cluster and portable.
FAQs
Where does CoreDNS store its config?
In the coredns ConfigMap in the kube-system namespace, under the Corefile key.
Do I need to restart CoreDNS after editing?
Usually no; the reload plugin applies changes within about two minutes, but a rollout restart forces it immediately.
How do I add a private DNS zone?
Add a new server block (stub domain) for that zone with its own forward to the internal resolvers.
Why is my external lookup slow?
Often ndots:5 causes multiple search-suffix attempts; use FQDNs or add cache and NodeLocal DNSCache.
How do I see CoreDNS metrics?
The prometheus :9153 plugin exposes metrics that Prometheus can scrape.
Is CoreDNS the node runtime's resolver too?
No; CoreDNS serves pods. Nodes use their own host resolver, and containerd runs the pods.
Related
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).