CoreDNS is the default DNS server for Kubernetes, but its true power lies in its ability to be configured as a dynamic, pluggable system that adapts to the complex networking needs of a cluster.
Let’s see it in action. Imagine a Kubernetes pod running an application that needs to resolve the service my-app.my-namespace.svc.cluster.local.
# Inside a Kubernetes pod with DNS configured
root@my-app-pod:/# nslookup my-app.my-namespace.svc.cluster.local
Server: 10.43.0.10
Address: 10.43.0.10#53
Name: my-app.my-namespace.svc.cluster.local
Address: 10.43.0.100
Here, 10.43.0.10 is the ClusterIP of the CoreDNS service, and 10.43.0.100 is the ClusterIP of the my-app service. CoreDNS, running as pods within the kube-system namespace, intercepts this nslookup query.
The fundamental problem CoreDNS solves in Kubernetes is providing a robust, Kubernetes-aware DNS resolution mechanism. In a traditional environment, DNS is largely static. In Kubernetes, pods are ephemeral, IP addresses change, and services are abstractions that need to be resolved to underlying pod IPs. CoreDNS handles this by integrating directly with the Kubernetes API.
Internally, CoreDNS operates as a chain of plugins. Each plugin is a Go program that receives a DNS request and can either respond to it, modify it, or pass it to the next plugin in the chain. The Corefile is the configuration that defines this chain.
Here’s a simplified Corefile typically found in Kubernetes:
.: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
}
Let’s break down the key plugins in this Corefile:
.:53: This is the main server block, listening on UDP and TCP port 53 for all zones (.).errors: Logs DNS query errors. Essential for debugging.health: Exposes a health check endpoint, useful for Kubernetes liveness and readiness probes.lameduck 5smeans it will wait 5 seconds before reporting unhealthy after a failure.ready: Exposes a readiness check endpoint, indicating if CoreDNS is ready to serve traffic.kubernetes: This is the star of the show for Kubernetes integration. It watches the Kubernetes API for Services, Endpoints, and Pods.cluster.local in-addr.arpa ip6.arpa: It’s configured to handle DNS queries for the cluster domain (cluster.local) and reverse lookups (in-addr.arpa,ip6.arpa).pods insecure: Specifies how to handle pod IP lookups.insecuremeans it will directly return pod IPs without requiring TLS verification, which is common in cluster-internal DNS.fallthrough in-addr.arpa ip6.arpa: If a reverse lookup doesn’t match a Kubernetes service or pod, it passes the query to the next plugin (in this case,forward).ttl 30: Sets the Time-To-Live for records managed by this plugin to 30 seconds.
prometheus: Exposes Prometheus metrics on port9153. This allows you to monitor CoreDNS performance and health.forward . /etc/resolv.conf: For any queries not handled by thekubernetesplugin (like external domain names), this forwards them to the upstream DNS servers configured in the pod’s/etc/resolv.conf.max_concurrent 1000: Sets a limit on concurrent upstream requests to prevent overwhelming upstream servers.
cache 30: Caches DNS responses for 30 seconds. This significantly reduces the load on upstream DNS servers and speeds up subsequent lookups for the same domain.loop: Detects and prevents DNS forwarding loops.reload: Automatically reloads theCorefilewhen it changes, without restarting the CoreDNS pods.loadbalance: For services with multiple backing pods, this plugin can distribute load across them by returning different IP addresses for the same A record.
The kubernetes plugin dynamically creates DNS records based on Kubernetes objects. When you create a Service named my-app in namespace my-namespace, the kubernetes plugin registers a DNS entry for my-app.my-namespace.svc.cluster.local that resolves to the Service’s ClusterIP. Similarly, it handles headless services by returning the IPs of the backing pods.
One aspect of CoreDNS configuration that often surprises people is how it handles external DNS resolution. Many assume it only talks to Kubernetes API. However, the forward plugin is crucial. If a pod queries google.com, the kubernetes plugin won’t have an entry, so the request falls through to forward. This forwards the query to whatever nameservers are listed in the pod’s /etc/resolv.conf (which is usually populated by the kubelet based on the node’s /etc/resolv.conf). This seamless integration means your cluster pods can resolve both internal Kubernetes services and external internet domains using the same DNS server.
The next common challenge is understanding how to customize CoreDNS for more advanced scenarios, like integrating with external DNS providers or implementing custom DNS policies.