CoreDNS is a DNS server that can be extended with plugins, making it incredibly flexible for complex networking scenarios like multi-cluster DNS.

Let’s see CoreDNS in action within a Kubernetes environment. Imagine you have two clusters, cluster-a and cluster-b, and you want pods in cluster-a to be able to resolve services in cluster-b using their internal Kubernetes DNS names (e.g., my-service.my-namespace.svc.cluster.local).

Here’s a simplified Corefile for cluster-a that achieves this:

.:53 {
    errors
    health {
       lameduck 5s
    }
    ready
    kubernetes cluster.local in-addr.arpa ip6.arpa {
       pods insecure
       fallthrough in-addr.arpa ip6.arpa
    }
    prometheus :9153
    cache 30
    forward . /etc/resolv.conf {
       max_concurrent 1000
    }
    # This is the key part for multi-cluster
    forward cluster-b.example.com {
       to <cluster-b-coredns-service-ip>:53
    }
}

Explanation:

  • .:53: This is the main configuration block, listening on all interfaces on port 53 (the standard DNS port).
  • errors, health, ready: These are standard CoreDNS plugins for logging errors, health checks, and readiness probes.
  • kubernetes cluster.local ...: This plugin handles DNS resolution for the local Kubernetes cluster, including services and pods. fallthrough ensures that if a name isn’t found locally, it’s passed to the next plugin.
  • prometheus :9153: Exposes DNS metrics for Prometheus.
  • cache 30: Caches DNS responses for 30 seconds to improve performance.
  • forward . /etc/resolv.conf ...: This is the default forwarder for any queries not handled by previous plugins. It typically points to the upstream DNS servers defined in the node’s /etc/resolv.conf.
  • forward cluster-b.example.com { to <cluster-b-coredns-service-ip>:53 }: This is the crucial directive for multi-cluster DNS. When CoreDNS in cluster-a receives a query for a domain ending in cluster-b.example.com (e.g., my-service.my-namespace.svc.cluster.local if cluster-b.example.com is an alias for cluster-b’s internal DNS domain), it will forward that query directly to the CoreDNS service in cluster-b.

The Problem Solved:

Without this configuration, pods in cluster-a wouldn’t know how to resolve hostnames belonging to cluster-b’s internal Kubernetes DNS zone. They’d hit a dead end after the kubernetes plugin in cluster-a failed to find the name. This forward directive acts as a bridge, telling cluster-a’s DNS to delegate resolution for cluster-b’s domain to cluster-b’s own DNS infrastructure.

Internal Mechanics:

When a pod in cluster-a queries for my-service.my-namespace.svc.cluster.local and your cluster.local domain is configured correctly in cluster-a, the kubernetes plugin handles it. If you were to query for another-service.another-ns.svc.cluster.b.example.com, the kubernetes plugin in cluster-a would not find it. The query would then proceed down the Corefile. It would eventually hit the forward cluster-b.example.com block. Because the query domain another-service.another-ns.svc.cluster.b.example.com matches the cluster-b.example.com block, CoreDNS in cluster-a sends the query over the network to the specified IP address and port of CoreDNS in cluster-b. cluster-b’s CoreDNS then processes the query using its own kubernetes plugin and returns the IP address of another-service back to cluster-a’s CoreDNS, which then returns it to the original pod.

Levers You Control:

  1. The Domain Name (cluster-b.example.com): This must be a unique domain that you designate for cluster-b. It’s common practice to use a subdomain of your overall managed domain.
  2. The Target IP (<cluster-b-coredns-service-ip>): This is the ClusterIP of the CoreDNS service in cluster-b. You can find this by running kubectl get svc -n kube-system coredns (or whatever namespace CoreDNS is deployed in) in cluster-b.
  3. The Corefile: This is the configuration file for CoreDNS. You’ll apply this to your CoreDNS deployment in cluster-a.
  4. Network Connectivity: Ensure that pods in cluster-a can reach the CoreDNS service IP and port in cluster-b over the network. This might involve VPC peering, VPNs, or other network configurations depending on your infrastructure.

The most surprising thing about setting up multi-cluster DNS is how simple the CoreDNS configuration itself often is, relying heavily on the forward directive. The complexity almost always lies in ensuring the network path is open and that the DNS domains are correctly mapped and unique across your clusters. You can even have bidirectional forwarding by adding a similar forward cluster-a.example.com block to cluster-b’s CoreDNS.

The next logical step is to configure service discovery for services that might span multiple regions, not just multiple clusters.

Want structured learning?

Take the full Coredns course →