DEV Community

Arnob
Arnob

Posted on

How CoreDNS Works!

CoreDNS is a fast, flexible, and extensible DNS server written in Go that is most famous for being the default cluster DNS for Kubernetes. It functions by chaining together a series of plugins, where each plugin performs a specific DNS action like caching, service discovery, or rewriting queries. The CoreDNS project is hosted by the CNCF.

captionless image

Its main job is:

  • Convert service names → IP addresses
  • Help containers/pods discover each other
  • Provide internal cluster networking resolution
  • Optionally forward external DNS requests to upstream DNS servers

Example:

A pod wants to connect to:

mysql.default.svc.cluster.local
Enter fullscreen mode Exit fullscreen mode

CoreDNS answers:

10.96.12.7
Enter fullscreen mode Exit fullscreen mode

So the pod can connect without knowing the actual IP.

Why CoreDNS Exists

In Kubernetes:

  • Pods are created/destroyed constantly
  • IPs change frequently
  • Hardcoding IP addresses is impossible

CoreDNS creates a dynamic DNS system for the cluster.

High-Level Architecture

+-------------------+
| Application Pod   |
| nginx pod         |
+---------+---------+
          |
          | DNS Query
          v
+-------------------+
| /etc/resolv.conf  |
| nameserver x.x.x.x|
+---------+---------+
          |
          v
+-------------------+
| CoreDNS Service   |
| kube-dns ClusterIP|
+---------+---------+
          |
          v
+-------------------+
| CoreDNS Pods      |
| DNS Engine        |
+---------+---------+
          |
   +------+------+
   |             |
   v             v
Kubernetes    External DNS
API Server    (8.8.8.8)
Enter fullscreen mode Exit fullscreen mode

What Happens Behind the Scenes

Suppose this pod runs:

curl http://backend-service
Enter fullscreen mode Exit fullscreen mode

Step 1 — Application Makes DNS Request

The Linux resolver library checks:

/etc/resolv.conf
Enter fullscreen mode Exit fullscreen mode

Inside pod:

nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local
Enter fullscreen mode Exit fullscreen mode

10.96.0.10 is the CoreDNS service IP.

Step 2 — Packet Goes to CoreDNS Service

The DNS request travels through:

  • veth pair
  • container namespace
  • CNI network
  • kube-proxy/IPVS/iptables

Eventually reaches CoreDNS pod.

Step 3 — CoreDNS Receives Query

Query example:

backend-service.default.svc.cluster.local
Enter fullscreen mode Exit fullscreen mode

CoreDNS parses the request.

CoreDNS Internal Pipeline

CoreDNS uses a plugin architecture.

Request flow:

DNS Request
     |
     v
+------------+
| log plugin |
+------------+
     |
+------------+
| cache      |
+------------+
     |
+------------+
| kubernetes |
+------------+
     |
+------------+
| forward    |
+------------+
Enter fullscreen mode Exit fullscreen mode

Each plugin processes the request.

Kubernetes Plugin

This is the important part.

CoreDNS queries the Kubernetes API:

GET /api/v1/services
GET /api/v1/endpoints
Enter fullscreen mode Exit fullscreen mode

It keeps an internal cache of:

  • Services
  • Pods
  • Endpoints
  • Namespaces

Internal Data Flow

+------------------+
| Kubernetes API   |
+--------+---------+
         ^
         | Watch API
         |
+--------+---------+
| CoreDNS           |
| Internal Cache    |
+--------+---------+
         ^
         |
DNS Query|
         |
+--------+---------+
| Application Pod  |
+------------------+
Enter fullscreen mode Exit fullscreen mode

CoreDNS watches the API continuously.

When a service changes:

  • Kubernetes notifies CoreDNS
  • Cache updates immediately

No database lookup is needed for every query.

Example Resolution

Service:

apiVersion: v1
kind: Service
metadata:
  name: backend
Enter fullscreen mode Exit fullscreen mode

Cluster IP:

10.96.20.15
Enter fullscreen mode Exit fullscreen mode

CoreDNS stores:

backend.default.svc.cluster.local
    ->
10.96.20.15
Enter fullscreen mode Exit fullscreen mode

When queried:

Q: backend.default.svc.cluster.local
A: 10.96.20.15
Enter fullscreen mode Exit fullscreen mode

External DNS Requests

If query is NOT cluster-local:

Example:

google.com
Enter fullscreen mode Exit fullscreen mode

CoreDNS forwards the request to:

  • /etc/resolv.conf
  • upstream DNS
  • 8.8.8.8
  • corporate DNS

Using the forward plugin.

Corefile (Configuration)

CoreDNS config:

.:53 {
    errors
    health
    kubernetes cluster.local
    forward . 8.8.8.8
    cache 30
}
Enter fullscreen mode Exit fullscreen mode

Meaning:

| Plugin     | Purpose         |
| ---------- | --------------- |
| errors     | log errors      |
| health     | health endpoint |
| kubernetes | cluster DNS     |
| forward    | external DNS    |
| cache      | cache responses |
Enter fullscreen mode Exit fullscreen mode

Deep Internal Architecture

              +----------------+
              | Kubernetes API |
              +--------+-------+
                       ^
                       |
                Watch/Informer
                       |
+------------------------------------------------+
|                CoreDNS Pod                     |
|                                                |
|  +------------------------------------------+  |
|  | DNS Listener :53                         |  |
|  +-------------------+----------------------+  |
|                      |                         |
|              Plugin Chain                      |
|                      |                         |
|   +--------+--------+--------+--------+        |
|   | cache  | kubernetes | forward | log|       |
|   +--------+--------+--------+--------+        |
|                      |                         |
|               Internal Memory Cache            |
+------------------------------------------------+
Enter fullscreen mode Exit fullscreen mode

How CoreDNS Scales

Usually, Kubernetes runs:

Deployment/coredns
Enter fullscreen mode Exit fullscreen mode

with multiple replicas.

Example:

coredns-abc
coredns-def
Enter fullscreen mode Exit fullscreen mode

The service load-balances requests.

Performance Optimizations

CoreDNS uses:

  • In-memory cache
  • Kubernetes informers/watch
  • UDP for fast queries
  • Minimal plugin chain
  • Concurrent request handling

Failure Scenario

If CoreDNS dies:

  • Pods cannot resolve service names
  • Internal networking breaks
  • Existing TCP connections still work

This is why production clusters run multiple replicas.

Important Kubernetes DNS Names

| Type             | Example                              |
| ---------------- | ------------------------------------ |
| Service          | mysql.default.svc.cluster.local      |
| Pod              | 10-1-2-3.default.pod.cluster.local   |
| Namespace search | mysql → auto-expanded                |
Enter fullscreen mode Exit fullscreen mode

If you wanted to add a private IP

If you want to add a custom private IP/domain mapping in CoreDNS, there are several ways depending on your goal.

Common example:

db.internal.local -> 192.168.10.50
Enter fullscreen mode Exit fullscreen mode

or:

gitlab.home.lab -> 10.0.0.15
Enter fullscreen mode Exit fullscreen mode

Easiest way Using hosts plugin.

Step 1 — Edit CoreDNS ConfigMap

Open CoreDNS config:

kubectl -n kube-system edit configmap coredns
Enter fullscreen mode Exit fullscreen mode

You will see:

Corefile:
Enter fullscreen mode Exit fullscreen mode

Step 2 — Add hosts Plugin

Example:

.:53 {
    errors
    health    hosts {
        192.168.10.50 db.internal.local
        10.0.0.15 gitlab.home.lab
        fallthrough
    }    kubernetes cluster.local in-addr.arpa ip6.arpa {
       pods insecure
       fallthrough in-addr.arpa ip6.arpa
    }    forward . /etc/resolv.conf
    cache 30
}
Enter fullscreen mode Exit fullscreen mode

What Happens Internally

DNS Query
    |
    v
+-----------+
| hosts     |  <-- checks static records
+-----------+
    |
    +--> Match found?
            |
            +--> Return private IP
            |
            +--> Otherwise continue
Enter fullscreen mode Exit fullscreen mode

fallthrough means:

“If no match found, continue to the next plugin.”

Step 3 — Restart CoreDNS

Usually automatic, but safest:

kubectl rollout restart deployment coredns -n kube-system
Enter fullscreen mode Exit fullscreen mode

Step 4 — Test

Inside pod:

nslookup db.internal.local
Enter fullscreen mode Exit fullscreen mode

Result:

Name: db.internal.local
Address: 192.168.10.50
Enter fullscreen mode Exit fullscreen mode

Architecture Behind It

Pod
 |
 | DNS Query
 v
CoreDNS
 |
 +--> hosts plugin
 |       |
 |       +--> static memory lookup
 |
 +--> kubernetes plugin
 |
 +--> forward plugin
Enter fullscreen mode Exit fullscreen mode

Real Networking Flow

Pod A
  |
  | DNS Query
  v
CoreDNS Service IP
  |
  v
CoreDNS Pod
  |
  +--> Kubernetes Cache
  |
  +--> Upstream DNS
  |
  v
DNS Response
  |
  v
Pod A connects to target
Enter fullscreen mode Exit fullscreen mode

CoreDNS is the default DNS server in Kubernetes clusters that provides dynamic service discovery between pods and services. Instead of relying on fixed IP addresses, applications communicate using DNS names such as mysql.default.svc.cluster.local, which CoreDNS resolves into cluster IPs.

Behind the scenes, CoreDNS acts as a plugin-based DNS engine that continuously monitors the Kubernetes API server for changes to services, pods, and endpoints. It maintains an in-memory cache of cluster resources, allowing fast DNS resolution without querying the API on every request. Requests pass through a plugin pipeline that can include caching, Kubernetes service discovery, logging, and forwarding to external DNS servers.

The blog also explains how to add custom private IP mappings into CoreDNS using multiple methods. The simplest approach uses the hosts plugin to statically map internal domains to private IP addresses. For larger environments, administrators can create custom DNS zones or use Kubernetes-native Service and Endpoints Resources to expose external systems through cluster DNS.

Overall, CoreDNS acts as the networking discovery layer of Kubernetes, combining DNS resolution, Kubernetes API integration, caching, and plugin extensibility to make container communication reliable and dynamic.

Top comments (0)