← DNS SoftwareDNS Software / Cloud Native

CoreDNS

A fast, flexible DNS server written in Go with a plugin-based architecture — the default DNS server in Kubernetes and a CNCF graduated project.

Overview

Plugin-Based DNS for Cloud Native

CoreDNS is built around a plugin chain — every DNS function is implemented as a plugin, and you compose a server by listing plugins in a Corefile. This makes CoreDNS extremely flexible: the same binary can act as an authoritative server, a forwarder, a caching resolver, or all three simultaneously on different ports.

Kubernetes uses CoreDNS as its in-cluster DNS service. Every Pod's DNS queries go through CoreDNS, which resolves Kubernetes Service names (service.namespace.svc.cluster.local) and forwards external queries upstream. Understanding CoreDNS configuration is essential for Kubernetes DNS troubleshooting.

  • Single Go binary — easy to deploy in containers, no external dependencies
  • Plugin chain: cache, forward, hosts, file, kubernetes, etcd, and 30+ more
  • Kubernetes plugin reads Service and Pod records directly from the API server
  • Prometheus metrics plugin for monitoring DNS query rates and latency
  • Health check endpoints (health plugin) for load balancer integration
  • DNS-over-TLS and DNS-over-HTTPS via tls plugin
  • Reload plugin for zero-downtime config changes
When to Choose CoreDNS
  • You are running Kubernetes (it's already there)
  • You need a lightweight containerized DNS server
  • You want plugin composability over monolithic config
  • You need etcd-backed dynamic DNS records
CNCF
Graduated project
K8s
Default Kubernetes DNS
Configuration

Corefile Examples

Default Kubernetes Corefile

# ConfigMap: coredns in kube-system .: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 }

Forwarder + caching server

# Forward all queries to upstream # with local caching .:53 { # Cache responses for 30s minimum cache 30 # Forward to Cloudflare over TLS forward . tls://1.1.1.1 tls://1.0.0.1 { tls_servername cloudflare-dns.com health_check 5s } # Prometheus metrics prometheus 0.0.0.0:9153 # Log queries log errors }

Split-horizon with file plugin

# Internal zone served from file corp.internal:53 { file /etc/coredns/db.corp.internal log errors } # Everything else forwarded upstream .:53 { forward . 8.8.8.8 8.8.4.4 cache 300 errors } # db.corp.internal zone file # (standard BIND zone format)

Troubleshoot K8s DNS

# Check CoreDNS pods are running kubectl -n kube-system get pods -l k8s-app=kube-dns # View CoreDNS logs kubectl -n kube-system logs -l k8s-app=kube-dns # Test DNS from a pod kubectl run dns-test --image=busybox:1.28 --rm -it \ --restart=Never -- nslookup kubernetes.default # Edit CoreDNS config kubectl -n kube-system edit configmap coredns # View current Corefile kubectl -n kube-system get configmap coredns -o yaml