CoreDNS is actually a pluggable DNS server, meaning it’s not a monolithic black box but a series of independent plugins that can be enabled or disabled to customize its behavior.

Let’s see CoreDNS in action, specifically how it handles a DNS query when configured as an Istio DNS proxy. Imagine a pod in your Istio mesh trying to resolve an external service, say example.com.

# From within an Istio-enabled pod
kubectl exec -it <pod-name> -c istio-proxy -- curl -v http://example.com

When the application inside the pod attempts to resolve example.com, the istio-proxy (Envoy) intercepts this DNS request. Envoy is configured by Istio to forward all DNS queries to a specific "DNS proxy" service. In a typical Istio setup, this DNS proxy service is CoreDNS itself, running as a deployment within the kube-system namespace (or wherever your Istio control plane is installed).

Here’s a simplified view of the CoreDNS Corefile that Istio might use for DNS proxying:

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

Let’s break down what’s happening here:

  • .:53: This is the main server block, indicating that CoreDNS is listening on UDP and TCP port 53 for DNS requests.
  • errors: This plugin logs errors encountered during DNS resolution.
  • health: This plugin provides a health check endpoint (typically on port 8080 or a configured port) to indicate if CoreDNS is ready to serve requests. lameduck 5s means it will wait 5 seconds before marking itself as unhealthy if it encounters issues.
  • ready: This plugin signals readiness to the Kubernetes health checking system.
  • kubernetes cluster.local in-addr.arpa ip6.arpa: This is the heart of CoreDNS’s integration with Kubernetes. It handles DNS queries for services and pods within the cluster.local domain, as well as reverse DNS lookups.
    • pods insecure: Allows resolution of pod IPs without strict validation.
    • upstream: If a query can’t be resolved by the Kubernetes plugin (e.g., it’s not a cluster-internal service), it will be passed to the next plugin.
    • fallthrough in-addr.arpa ip6.arpa: Ensures that reverse DNS queries are also handled by the Kubernetes plugin.
  • prometheus :9153: Exposes Prometheus metrics on port 9153, which Istio can scrape to monitor DNS performance.
  • forward . /etc/resolv.conf { max_concurrent 1000 }: This is crucial for handling external DNS queries.
    • forward . /etc/resolv.conf: For any query (.) that wasn’t handled by the preceding kubernetes plugin, CoreDNS will forward it to the upstream DNS servers defined in the pod’s /etc/resolv.conf (which typically points to the cluster’s DNS service, like kube-dns or another CoreDNS instance).
    • max_concurrent 1000: Limits the number of concurrent forward requests to 1000, preventing overload.
  • cache 30: Caches DNS responses for 30 seconds, reducing the load on upstream DNS servers and speeding up subsequent lookups for the same domain.
  • loop: Detects and prevents DNS loops.
  • reload: Automatically reloads the Corefile if it changes, without requiring a CoreDNS restart.
  • loadbalance: Distributes queries across multiple upstream servers if specified.

When a query for example.com arrives, CoreDNS first checks if it’s a Kubernetes-internal name. Since it’s not, the kubernetes plugin falls through. The forward plugin then takes over and sends the query to the upstream DNS server (e.g., your cloud provider’s DNS resolver or your local network’s DNS). The response is then cached and returned to the application via Envoy.

The most surprising true thing about CoreDNS, especially when used with Istio, is that it’s not primarily resolving external names itself; it’s acting as a sophisticated router and cacher for DNS requests, intelligently deciding whether to handle it locally (for Kubernetes services) or pass it upstream.

The next concept you’ll likely encounter is how to customize this behavior further, perhaps by specifying custom upstream DNS servers for specific domains or by integrating with external DNS providers.

Want structured learning?

Take the full Coredns course →