CoreDNS, when acting as the Kubernetes DNS service, doesn’t just look up A records; it’s actively querying the Kubernetes API for information about Services and Endpoints.

Let’s see it in action. Imagine you have a frontend Service and a backend Service, and your application needs to talk to backend.default.svc.cluster.local.

apiVersion: v1
kind: Service
metadata:
  name: backend
  namespace: default
spec:
  selector:
    app: backend
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-1
  labels:
    app: backend
spec:
  containers:
  - name: backend
    image: nginx
    ports:
    - containerPort: 8080
---
apiVersion: v1
kind: Pod
metadata:
  name: backend-pod-2
  labels:
    app: backend
spec:
  containers:
  - name: backend
    image: nginx
    ports:
    - containerPort: 8080

When a pod in your cluster queries for backend.default.svc.cluster.local, CoreDNS, configured with the kubernetes plugin, doesn’t perform a standard DNS lookup. Instead, it makes a request to the Kubernetes API server.

Here’s a simplified trace of what CoreDNS might do internally:

  1. Receive Query: A pod sends a DNS query for backend.default.svc.cluster.local.
  2. Plugin Match: The kubernetes plugin in CoreDNS matches this query pattern.
  3. API Query (Service): CoreDNS asks the Kubernetes API for a Service named backend in the default namespace.
  4. API Query (Endpoints): If the Service is found, CoreDNS then asks the Kubernetes API for the Endpoints associated with that Service. Endpoints are essentially the IP addresses of the pods that match the Service’s selector.
  5. Construct Response: CoreDNS takes the IP addresses from the Endpoints and constructs an A record response. If there are multiple backend pods, CoreDNS will round-robin between their IPs. For a headless service, it would return the pod IPs directly.

The kubernetes plugin is configured within your CoreDNS Corefile. A typical configuration for a cluster looks like this:

.: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
    cache 30
    loop
    reload
    loadbalance
}

The crucial part is the kubernetes directive. cluster.local is the cluster domain. pods insecure means it won’t verify TLS for the API connection (common in many setups). upstream tells CoreDNS to forward queries that don’t match the kubernetes plugin’s scope to the upstream resolvers (usually your node’s /etc/resolv.conf). fallthrough ensures that reverse DNS lookups (in-addr.arpa) are handled by the upstream if the kubernetes plugin doesn’t have specific entries for them.

The kubernetes plugin’s magic lies in its ability to translate DNS queries into API calls. It watches the Kubernetes API for changes to Services and Endpoints. When a pod is created or deleted, or a Service’s selector changes, CoreDNS is notified and updates its internal cache of these resources. This allows for near real-time DNS resolution that reflects the dynamic state of your cluster.

The cluster.local suffix is configurable. If your cluster uses a different domain, like mycorp.local, you’d update this in your Corefile and ensure all your Service FQDNs reflect that.

The kubernetes plugin also handles reverse DNS lookups (in-addr.arpa and ip6.arpa). When a pod queries for the IP address of a service, CoreDNS can translate that IP back to the service name by querying the API for the corresponding Service and Pod information. This is handled by the in-addr.arpa and ip6.arpa parts of the directive.

What most users don’t realize is that the kubernetes plugin is not just a static DNS server; it’s a dynamic cache that relies heavily on the Kubernetes API server’s watch mechanism. If the API server is slow or unavailable, CoreDNS will struggle to resolve service names, even if the DNS server itself is healthy. The prometheus endpoint provides metrics on API request latency and cache hit rates, which are invaluable for debugging.

Once you’ve mastered service resolution, you’ll want to understand how CoreDNS handles external DNS lookups and the nuances of the forward plugin.

Want structured learning?

Take the full Coredns course →