DNS Internals: A CoreDNS Deep Dive in Kubernetes

DNS Internals: A CoreDNS Deep Dive in Kubernetes

How a simple name like "orders" becomes the right address inside a cluster that changes every second, what CoreDNS does at each step, and how to keep it fast and reliable.

Picture a huge office building where people move desks every day. Nobody can remember where anyone sits, so instead of memorizing desk numbers, everyone calls the reception desk and says, “Connect me to Accounts.” Reception looks at a live seating chart, finds who is in Accounts today, and gives out the right extension. If reception is slow or has an old chart, every call in the building suffers. And if reception does not know a name, it phones an outside directory service to ask.

Kubernetes has exactly such a reception desk. It is called the cluster DNS, and the program that runs it is CoreDNS. In this guide you will learn what DNS is, why Kubernetes needs its own, how CoreDNS builds its seating chart, how a single lookup travels from your application to an answer, and why a hidden setting called ndots can quietly multiply your traffic. You will also learn how caching, NodeLocal DNSCache, scaling and monitoring keep the whole thing healthy. Every new word is explained the first time it appears, so you can start from zero.

1Why a Cluster Needs Its Own Phone Book

Before opening the Corefile, we need to understand the problem DNS solves, and why the ordinary internet version is not enough inside a cluster.

What DNS is, in plain words

Computers talk to each other using numbers called IP addresses, such as 10.96.14.7. People prefer names, such as “orders” or “example.com”. The Domain Name System, or DNS, is the worldwide phone book that turns names into numbers. When your application wants to talk to “example.com”, a small piece of code inside it, called the resolver, sends a question to a DNS server: “What is the address for this name?” The server replies with an answer and a number saying how long the answer may be remembered, called the TTL, short for time to live.

Why Pods cannot just use IP addresses

In Kubernetes, your application runs in Pods, the smallest units of work, each with its own IP address. But Pods are temporary. They are created, destroyed and replaced all the time, during updates, failures, and scaling. Every new Pod gets a different IP address. If the “checkout” service saved the IP of the “payments” Pod yesterday, that address might belong to nothing, or to a different application, today.

Kubernetes solves part of this with a Service, a stable front door with a fixed virtual IP, called the ClusterIP, which spreads traffic across the Pods behind it. But a fixed IP is still a number to remember, and it changes if the Service is recreated or moved to another environment. What you really want is a stable name. Cluster DNS gives every Service a name that always works, in every environment, from every Pod.

Everyday analogy

Think of a courier company that lets you send a parcel to “Priya at Finance” rather than to a desk number. The desk number changes monthly. The name does not. Reception, the DNS, translates the name to today’s desk. The sender never has to know that Priya moved.

Where CoreDNS came from

The first Kubernetes DNS add-on was called kube-dns. It was built from several programs working together, including a general-purpose DNS cache called dnsmasq. It worked, but it was hard to extend and had memory and performance quirks. The community then adopted CoreDNS, a DNS server written in Go that is built entirely from small plugins chained together. CoreDNS became the default in Kubernetes around version 1.13 and is now the standard on nearly every distribution. For compatibility, the Service in front of it is still named “kube-dns”, which surprises many newcomers.

53
the standard DNS port, used over both UDP and TCP
5
the default “ndots” value in Pods, a setting that shapes DNS traffic
9153
the port where CoreDNS publishes its metrics for monitoring
1

Hand-edited host files

In the earliest networks, one text file listed every computer. It could not scale to a changing cluster.

2

Environment variables

Early Kubernetes injected Service addresses into Pods as variables. These were only set at Pod start, so later Services were invisible.

3

kube-dns

A cluster DNS add-on gave every Service a name that updates live, using a few cooperating programs.

4

CoreDNS as default

A single plugin-based server replaced kube-dns, simpler to run and far easier to customize.

5

Node-level caching and managed add-ons

NodeLocal DNSCache and cloud-managed CoreDNS add-ons appeared to handle very large clusters.

i
Good to know

When people say “Kubernetes DNS is slow” or “DNS is down,” in most cases they mean one of three things: CoreDNS is overloaded, the traffic from Pods is far larger than it needs to be, or an upstream resolver outside the cluster is throttling. This guide covers all three.

2Core Concepts: The Vocabulary You Need

A short glossary makes every later chapter easier to read.

TermWhat it meansEveryday picture
ResolverThe code inside an application (or its operating system library) that asks DNS questions.The person dialing reception.
NameserverA server that answers DNS questions.The reception desk itself.
RecordOne entry in DNS, such as a name and its address.One line in the phone book.
A / AAAA recordMaps a name to an IPv4 (A) or IPv6 (AAAA) address.“Priya: extension 4021.”
CNAME recordAn alias that points one name to another name.“For billing, ask for Finance.”
SRV recordGives both a host and a port for a service.“Reception for sales is on line 3, extension 88.”
PTR recordMaps an address back to a name (reverse lookup).Caller ID.
TTLHow long an answer may be remembered.“This number is valid for 30 seconds.”
NXDOMAINThe answer “that name does not exist.”“No such person here.”
Search domainA suffix automatically added to short names.Adding “at our company” to every name.
ndotsThe number of dots below which a name is treated as short and gets suffixes first.A rule: “if the name looks short, try local first.”
CorefileCoreDNS’s configuration file.The reception desk’s instruction sheet.
PluginOne small feature of CoreDNS, such as caching or forwarding.One step on the receptionist’s checklist.
Headless ServiceA Service with no virtual IP, whose name returns the Pods’ own addresses.A directory that lists every person in a team, not a single switchboard line.

The anatomy of a cluster name

Every Service in the cluster has a full name built from four parts, read from the most specific to the most general: the Service name, the namespace it lives in, the word svc, and the cluster domain, which is cluster.local by default. So a Service called “orders” in the “shop” namespace has the full name orders.shop.svc.cluster.local. A name that is spelled out completely like this is called a fully qualified domain name, or FQDN.

You rarely type the full form. Inside the “shop” namespace you can just say “orders”. From another namespace you can say orders.shop. The shorter forms work because of the search domains that Kubernetes places inside every Pod, which we examine in Chapter 7.

Everyday analogy

Think of postal addresses. “Priya” is enough inside your own office. “Priya, Finance” works within your company. “Priya, Finance, Acme Corp, Bengaluru” works from anywhere in the world. The cluster name is the full postal address, and the search domains are the habit of filling in the missing parts for you.

?
Namespaces are not walls

The namespace appears in the DNS name, but it does not hide anything. Any Pod can look up any Service in any namespace if it knows the name. Namespaces organize names; they do not isolate them. Isolation needs network policy, which we cover in the security chapter.

3Architecture: The Pieces of Cluster DNS

Cluster DNS is not one magic box. It is a small set of ordinary Kubernetes objects working together.

flowchart LR
  APP["Application in a Pod"] --> RES["Resolver library reads resolv.conf"]
  RES -->|query to kube-dns ClusterIP| SVC["kube-dns Service"]
  SVC -->|load balanced by kube-proxy| CD["CoreDNS Pod replicas"]
  CD --> KP["kubernetes plugin: in memory view of Services and EndpointSlices"]
  CD --> FW["forward plugin: upstream resolvers"]
  API["API server"] -->|list and watch| KP
  FW --> UP["Node or VPC resolver and the wider internet"]
    
Figure 1: The main components of Kubernetes cluster DNS, from the application to the outside world.

Read the diagram from left to right. An application asks its resolver a question. The resolver reads a small file, /etc/resolv.conf, to learn where the nameserver is. That address is the virtual IP of the kube-dns Service. Behind the Service run several CoreDNS Pods. Inside each, the kubernetes plugin holds a live picture of the cluster, built by watching the API server, and the forward plugin knows how to pass other questions to outside resolvers.

Config

The kubelet setting

The kubelet, the agent on each node, is told the DNS Service address and the cluster domain. It writes them into every Pod’s resolv.conf at start-up.

Front door

The kube-dns Service

A normal Service with a fixed virtual IP, usually the tenth address of the Service range. It exposes UDP and TCP port 53 and spreads queries across CoreDNS Pods.

Workers

CoreDNS Deployment

Usually two or more replicas in the system namespace. Each one is independent and holds its own copy of cluster data and its own cache.

Settings

The Corefile ConfigMap

The configuration lives in a ConfigMap that is mounted into the Pods. Edit it, and CoreDNS can reload without a restart.

Data

The kubernetes plugin

Watches Services, endpoint slices and namespaces through the API server and answers cluster questions from memory.

Access

RBAC permissions

A role that lets CoreDNS read Services and endpoints, and nothing more. It never needs to write anything.

Why the Service is called kube-dns

Older programs and tools look for a Service named “kube-dns” in the system namespace, so the name was kept when CoreDNS replaced the old implementation. If you run kubectl get svc -n kube-system and see kube-dns, do not worry, it is front-ending CoreDNS. The Pods carry a label with the same old name for the same reason.

Two layers of high availability

CoreDNS Pods are normal Pods and can be rescheduled, and the Service in front of them spreads queries between the healthy ones. So DNS survives the loss of a Pod or a node. But it is only as strong as the replica count and placement. A cluster with a single CoreDNS Pod has a single point of failure, and a cluster with two replicas that both land on one node is nearly as fragile. We return to this in the reliability chapter.

Everyday analogy

A hotel has one published reception number, but several receptionists sit behind it. A caller never chooses which one answers. The phone system (kube-proxy) hands each call to a free person. All of them read from the same live guest list, which is kept up to date by the manager (the API server).

Production example: the managed add-on

On Amazon EKS, CoreDNS is offered as a managed add-on, so AWS handles versions and patching while you adjust the Corefile and the replica settings. On Google GKE, the default is the older kube-dns, with options to use CoreDNS or Cloud DNS. The names and mechanics shown in this guide are the same everywhere; only who operates the pieces differs.

4Internal Working: The Life of One DNS Query

Let us follow a single lookup, for the name “orders”, from the moment the application asks to the moment it gets an address.

1

The application opens a connection by name

Code calls a library function, such as “connect to orders on port 8080”. The library needs an address first.

2

The resolver reads resolv.conf

It finds the nameserver address (the kube-dns Service IP), the list of search domains, and the ndots option.

3

The name is expanded

“orders” has no dots, which is fewer than ndots, so the resolver tries the search domains first: orders.shop.svc.cluster.local comes first, because the Pod lives in the “shop” namespace.

4

The query leaves the Pod

A small UDP packet is sent to the kube-dns Service IP on port 53. It usually asks for both an IPv4 (A) and an IPv6 (AAAA) answer.

5

The Service picks a CoreDNS Pod

kube-proxy rules on the node rewrite the destination from the virtual IP to the address of one healthy CoreDNS Pod. This step is a form of address translation.

6

CoreDNS runs its plugin chain

The cache is checked; on a miss, the kubernetes plugin finds the Service in memory and builds the answer: its ClusterIP.

7

The answer returns and is remembered

The resolver gets the IP with a TTL, hands it to the application, and the connection begins. CoreDNS also remembers the answer in its cache for the next asker.

How CoreDNS knows the answer without asking anyone

The key to speed is that CoreDNS does not query the API server for every lookup. The kubernetes plugin keeps a live in-memory copy of all Services, endpoint slices and namespaces, kept fresh by the same list-and-watch pattern used by other Kubernetes components. When you create a Service, the API server announces it, the plugin updates its memory within a moment, and the next query for that name succeeds. A lookup is then just a quick search in memory, which takes microseconds.

Cluster names versus outside names

CoreDNS sorts questions by zone, which means the part of the name tree it is responsible for. Names ending in cluster.local belong to the kubernetes plugin. Anything else, such as example.com or a cloud database endpoint, is passed to the forward plugin, which asks outside resolvers, usually the ones the node itself uses.

Inside

Cluster names

Answered from memory, very fast, no network call beyond the Pod-to-CoreDNS hop.

Outside

External names

Need a trip to an upstream resolver unless a recent answer is cached. This is where most latency lives.

Failure

Unknown names

If a cluster name does not exist, CoreDNS replies NXDOMAIN. Resolvers then move on to the next search domain, which matters a lot for traffic.

Everyday analogy

Reception first checks the building’s seating chart pinned on its own wall (the kubernetes plugin). If the name is not part of the building at all, say “Mr. Sharma at another company,” reception phones an outside directory (the forward plugin). It also scribbles recent answers on a sticky note (the cache), so the next caller asking the same question gets an instant reply.

i
Tip

DNS uses the small UDP protocol by default, which has no connection set-up cost. If an answer is too large for one packet, the server flags it as truncated and the resolver retries over TCP. Large headless Services with many Pods can trigger this, so make sure both UDP and TCP port 53 are allowed.

5The Records CoreDNS Creates

Different kinds of Kubernetes objects produce different DNS answers. Knowing the pattern lets you predict any name.

ObjectName patternWhat the answer is
Normal Serviceservice.namespace.svc.cluster.localOne A (and AAAA) record: the Service’s ClusterIP.
Headless ServiceSame nameSeveral A records: the IPs of each ready Pod behind it.
Named Service port_portname._protocol.service.namespace.svc.cluster.localAn SRV record: host name and port number.
StatefulSet Pod via headless Servicepod-0.service.namespace.svc.cluster.localThe stable address of that one Pod.
Pod (when enabled)1-2-3-4.namespace.pod.cluster.localThe Pod’s IP, written with dashes.
ExternalName ServiceSame pattern as a ServiceA CNAME pointing to an outside name.
Reverse lookupSpecial reverse zonesA PTR record naming the Service or Pod.

Normal Services: one stable address

For a typical Service, the answer is the ClusterIP, a virtual address that never changes during the Service’s life. The client connects to that address, and kube-proxy on the node spreads the connection across real Pods. The DNS answer does not change when Pods come and go, which is why DNS caching for ordinary Services is safe and cheap.

Headless Services: the directory, not the switchboard

A headless Service is one created without a ClusterIP. For it, DNS returns the addresses of the actual Pods, one A record per ready Pod. The client sees the list and can choose, or connect to all. This is how databases and message brokers let their members find each other. Because the list changes whenever Pods change, TTLs matter much more here, and caching clients can hold stale answers.

By default, only Pods that are ready appear in these answers. Some systems, especially during start-up of a clustered database, need peers to find each other before any of them are ready. For those, the Service can be told to publish not-ready addresses as well.

Everyday analogy

A normal Service is a company’s main phone number: you always dial the same number, and a switchboard connects you to whoever is free. A headless Service is a staff list: asking for “Support” gives you the personal numbers of everyone on shift, and you decide whom to call.

StatefulSets and stable identities

A StatefulSet gives each Pod a permanent name with a number, like db-0, db-1, db-2. Paired with a headless Service, each Pod also gets its own DNS name, such as db-0.db.shop.svc.cluster.local. Even if db-0 is rebuilt on another node with a new IP, the name stays the same and the DNS record is updated. This is why databases and clustered systems depend on StatefulSets.

SRV records: names and ports together

When a Service port has a name, CoreDNS also creates an SRV record. An SRV answer carries both the host name and the port number, so a client does not need to know the port in advance. This is useful for service discovery in tools that look up ports dynamically.

ExternalName: an alias to the outside world

A Service of type ExternalName has no Pods and no virtual IP. Instead, DNS answers with a CNAME alias pointing to an outside name, for example a managed database hostname. Your applications use the stable in-cluster name, and you can change the outside target in one place. Note that it is purely a DNS trick. No traffic is proxied, and if the target needs special certificate names, they are checked against the outside name.

Pod records

CoreDNS can also answer for individual Pods using a name made from the Pod’s IP with dashes instead of dots. This is controlled by a setting in the kubernetes plugin. It is rarely needed by applications and is more commonly turned on for compatibility with older tools.

!
Watch out

An ExternalName Service gives a CNAME, and CNAMEs cannot be used at certain places in DNS. Some HTTP clients also send the original in-cluster name as the Host header, which the outside server may reject. Test it before relying on it.

6The Corefile and the Plugin Chain

Everything CoreDNS does is a plugin, and the Corefile is the instruction sheet that turns plugins on and tunes them.

flowchart TD
  Q["Query arrives at CoreDNS"] --> E["errors, prometheus, health: housekeeping"]
  E --> CA{"cache has a fresh answer?"}
  CA -->|yes| A1["Reply from cache"]
  CA -->|no| K{"kubernetes plugin owns this zone?"}
  K -->|yes| A2["Answer from in memory Services and Pods"]
  K -->|no| FW["forward plugin asks upstream resolvers"]
  A2 --> ST["cache stores the answer"]
  FW --> ST
  ST --> A3["Reply to client"]
    
Figure 2: How a query moves through the main plugins of a typical Kubernetes Corefile.

Read the diagram from the top. A query enters and passes through housekeeping plugins that record errors and metrics. The cache is checked first; a fresh answer is returned at once. Otherwise, if the name belongs to the cluster zone, the kubernetes plugin answers from memory. If not, the forward plugin asks an outside resolver. Either way, the new answer is stored in the cache before the reply goes back.

How the file is organized

A Corefile is made of server blocks. Each block names a zone and a port, such as “everything, on port 53”, and lists the plugins that apply to it. The standard Kubernetes Corefile has one server block for all names. You can add more blocks to send particular domains, like your company’s internal domain, to special servers. Each plugin inside a block can carry its own settings.

?
Order in the file does not set the order of execution

This surprises almost everyone. The sequence of plugins is fixed when CoreDNS is built, not by the order of lines in the Corefile. You choose which plugins are active, but you cannot reorder them by moving lines around. Cache always comes before kubernetes, and forward always comes after it.

The plugins in a default setup

Health

errors

Prints errors to the log so you can see failures such as upstream timeouts.

Health

health and ready

Provide web endpoints that Kubernetes uses for liveness and readiness checks. The health plugin can be set to wait a few seconds before stopping, giving traffic time to drain.

Core

kubernetes

Answers all names under the cluster domain, plus reverse lookups, by watching the cluster.

Metrics

prometheus

Exposes counters and timers on port 9153 for monitoring systems.

Outside

forward

Sends anything the cluster does not own to upstream resolvers, by default those listed in the node’s own resolver file.

Speed

cache

Remembers answers for a short time (often thirty seconds) to avoid repeated work.

Safety

loop

Detects when a query is being forwarded round and round, and stops CoreDNS rather than letting it spin.

Ops

reload

Watches the Corefile and loads changes without a restart, usually within a minute or two.

Fairness

loadbalance

Shuffles the order of address records in answers so clients do not all pick the first one.

Customizing: the common recipes

1

Send one domain to a special server

Add a server block for your company’s internal domain and forward it to the corporate DNS servers. Everything else continues as before. People call this a stub domain.

2

Rewrite a name

The rewrite plugin changes a name before lookup, so old names keep working after a Service is renamed.

3

Add fixed entries

The hosts plugin answers from a small list of fixed names and addresses, handy for a few special cases.

4

Change upstream resolvers

Point the forward plugin at specific servers instead of the node’s defaults, and choose how it spreads load across them.

5

Turn on query logging, carefully

The log plugin writes a line for every query. It is superb for debugging and terrible to leave on in a busy cluster.

Everyday analogy

The reception desk has an assembly-line checklist printed in a fixed order by the head office: greet, check the sticky notes, check the building chart, phone the outside directory, write the answer on a sticky note, reply. Local staff can choose which items to use and how strictly, but they cannot swap steps around.

!
Watch out

A mistake in the Corefile can bring down DNS for the whole cluster. Test changes in a staging cluster first, apply them while watching the CoreDNS logs, and keep a copy of the working version. A broken file usually makes CoreDNS refuse to reload, keeping the old working configuration, but do not count on it.

7Inside the Pod: resolv.conf, dnsPolicy and the ndots Trap

Half of all DNS problems in Kubernetes are not caused by CoreDNS at all. They come from what the Pod is told to do before the query is even sent.

What is inside a Pod’s resolver file

When the kubelet creates a Pod, it writes a small text file into it called /etc/resolv.conf. A typical file contains three kinds of lines. A nameserver line holds the address of the cluster DNS Service. A search line lists suffixes to try on short names, usually three: the Pod’s own namespace followed by svc.cluster.local, then svc.cluster.local, then cluster.local. Your cloud’s own search domains are often added after those. An options line contains ndots:5.

dnsPolicy: choosing how a Pod gets this file

dnsPolicyWhat the Pod getsUse it when
ClusterFirst (the default)Cluster DNS first; names outside the cluster go upstream through CoreDNS.Almost always.
ClusterFirstWithHostNetSame as above, but for Pods that use the node’s network directly.Pods with host networking that still need Service names.
DefaultThe node’s own resolver settings; no cluster names.Pods that must not use cluster DNS. The name is misleading, because this is not the default.
NoneNothing from Kubernetes; you supply everything in dnsConfig.Full manual control.
!
Watch out

A Pod that uses host networking and keeps the default policy silently falls back to the node’s DNS and cannot resolve Service names. If a host-network Pod cannot find a Service, check for ClusterFirstWithHostNet first.

dnsConfig: small adjustments

With the dnsConfig field you can add extra nameservers, extra search domains, or options like a lower ndots, either on top of the default policy or as a complete replacement under None. Be aware of limits: the common C library only honours three nameservers, and Kubernetes warns when the search list exceeds six entries or 256 characters in total.

The ndots trap, step by step

The ndots option says: “If a name has fewer than this many dots, treat it as a short name and try the search suffixes first.” With the default of 5, almost every ordinary name counts as short. The name example.com has one dot. api.payments.example.com has three. Both are below five. So the resolver walks the whole search list before trying the name as written.

flowchart TD
  N["App looks up example.com"] --> D{"Fewer dots than ndots 5?"}
  D -->|yes| S1["Try example.com.default.svc.cluster.local: NXDOMAIN"]
  S1 --> S2["Try example.com.svc.cluster.local: NXDOMAIN"]
  S2 --> S3["Try example.com.cluster.local: NXDOMAIN"]
  S3 --> S4["Try node search domains: NXDOMAIN"]
  S4 --> S5["Finally try example.com as written: success"]
  D -->|no| S5
    
Figure 3: How the search list turns one external lookup into several failed lookups before the real one succeeds.

Follow the diagram. The application only wanted one answer. But the resolver first asks for example.com with the Pod’s namespace suffix, gets “does not exist”, tries the next suffix, gets “does not exist” again, and so on, finally succeeding on the original name. And because most resolvers ask for both IPv4 and IPv6 addresses, every one of those attempts is doubled. A single external lookup can therefore turn into roughly ten packets, of which about eight are wasted.

Everyday analogy

You want to call “Mr. Sharma at Acme”. A very careful assistant first rings the internal directory for “Mr. Sharma at Acme in Finance”, then “Mr. Sharma at Acme in the company”, then “Mr. Sharma at Acme in the group”, and only after all those fail rings the external number. Each failed call is cheap on its own, but a hundred assistants doing it all day keep the switchboard busy.

Why the default is five

The value exists so that short, natural names like orders.shop.svc (two dots) get completed by the search list. Cluster names can have up to four dots in their usual forms, so five ensures that any partially written cluster name is completed before an outside lookup is tried. It is a good default for cluster-internal traffic and a costly one for traffic that goes outside.

Ways to tame it

Easiest

Use a trailing dot

Writing example.com. with a final dot marks the name as absolute. The resolver skips the search list. Works in configuration files where you control the hostnames.

Per Pod

Lower ndots

Set the ndots option to 2 in the Pod’s DNS settings. Cluster names written as service.namespace still work, and external names go straight out. Test your own naming habits first.

Server side

The autopath plugin

CoreDNS can walk the search list on the server, returning the final answer in one round trip. It needs the Pod lookup mode to be verified and costs extra memory, so use it with care.

Node side

NodeLocal DNSCache

A cache on each node absorbs the repeated failures without leaving the machine. Covered in Chapter 10.

Habit

Use full names for cluster Services

Using the fully qualified form for in-cluster Services, with the trailing dot, avoids waste in both directions.

Habit

Reuse connections

Pooled, long-lived connections need DNS far less often than code that opens a new connection for every request.

i
Tip

Before changing ndots everywhere, measure. Count the NXDOMAIN responses in CoreDNS metrics. If they make up a large share of all replies, the search list is costing you real capacity, and a small change will pay off quickly.

8The kubernetes Plugin Deep Dive

This plugin is the heart of cluster DNS. Understanding its settings explains most of the behaviour you will see.

How it stays up to date

When CoreDNS starts, the kubernetes plugin asks the API server for a full list of Services, endpoint slices and namespaces, then opens a watch to hear about changes. It builds in-memory tables indexed by name. This is the same list-and-watch pattern used across Kubernetes. If the watch drops, it reconnects and refreshes; if the API server is unreachable for a while, CoreDNS keeps answering from the last copy it has, so brief control-plane trouble does not break existing lookups.

Notice the cost of this design: each CoreDNS replica holds a copy of the whole Service and endpoint data of the cluster, so memory use grows with the number of Services and Pods, and each replica holds its own watch on the API server.

Endpoint slices, not whole Endpoints

For headless Services and for SRV records, CoreDNS needs the list of Pod addresses behind a Service. It reads these from endpoint slices, which are small groups of endpoint addresses that Kubernetes keeps for each Service. Slices keep the data compact and make updates cheaper than the older single-record form, which matters for Services with thousands of Pods.

The settings that matter

SettingWhat it doesNotes
podsControls Pod IP-style names. Disabled returns nothing; insecure answers any dashed IP; verified checks that the Pod really exists.Verified costs more memory but is safer.
ttlHow long clients may remember cluster answers.Small values mean fresher answers and more traffic.
fallthroughLets unknown names in certain zones (such as reverse zones) continue to the next plugin.Needed for reverse lookups to work with forwarding.
namespacesLimits which namespaces are exposed through DNS.Reduces what can be discovered.
endpoint_pod_namesUses Pod names rather than dashed IPs for headless records.Handy for debugging.
Multiple zonesThe plugin can serve more than one cluster domain.Useful during domain migrations.

Freshness: how quickly DNS follows reality

There is a short delay between a change in the cluster and the matching DNS change. The API server must announce the change, the plugin must update its memory, and any copy already cached in CoreDNS or in clients must expire. CoreDNS publishes a metric for the first part, often called the DNS programming latency, measuring how long it takes from the moment a change happens to the moment DNS reflects it. In a healthy cluster the figure is small, typically well under a second, but it rises when the API server or the nodes are overloaded.

1

A Service is created

The API server stores it and announces it to anyone watching.

2

Each CoreDNS replica hears about it

Its plugin adds the new Service to memory.

3

Negative caches may still say “no”

If someone asked for the name a moment earlier, the “does not exist” answer might still be cached until it expires.

4

Clients see the new name

Once caches expire, lookups succeed everywhere.

Everyday analogy

The seating chart on reception’s wall is updated the moment HR announces a move. But a colleague who looked up “Priya” five minutes ago might still carry the old extension on a scrap of paper. The wall chart is current within seconds; scraps of paper take longer to go out of date.

Production example: StatefulSets and databases

Clustered systems such as Kafka, Cassandra and etcd commonly run as StatefulSets with a headless Service. Their members find each other by the stable per-Pod DNS names created by the kubernetes plugin. When a member restarts with a new IP, the plugin updates the record, and the other members, if they re-resolve, reconnect. This is why such systems are careful about DNS caching in their own clients.

!
Watch out

Setting the Pod mode to insecure means CoreDNS will answer for any dashed address even if no such Pod exists. This is a convenience for old tools, but a gap if anything trusts those answers as proof of a Pod’s existence.

9Forwarding, Upstreams and Caching

For every name outside the cluster, CoreDNS becomes a middle-man. How well it plays that role decides most of your real-world latency.

The forward plugin

The forward plugin sends questions it cannot answer to one or more upstream resolvers. By default these are the servers listed in the CoreDNS Pod’s own resolver file, which comes from the node. On a cloud network that is usually the cloud provider’s built-in resolver for the private network. You can instead name specific servers, send some domains to your own corporate servers, and choose how to spread load among several upstreams: randomly, in turn, or always trying the first before falling back.

The plugin also checks the health of upstreams. If one stops responding, it is skipped for a while. And a setting caps the number of queries in flight at once, so a slow upstream cannot cause CoreDNS to pile up an unbounded backlog of waiting queries.

Loops: when DNS asks itself

A forwarding loop is a classic trap. Suppose the node’s resolver file points at a local helper on the node, a common arrangement on some Linux distributions. CoreDNS copies that setting, forwards a query to it, and the helper hands the query back to the cluster DNS because it was configured that way. The query circles forever. The loop plugin sends itself a test query at start-up, notices the echo, and shuts CoreDNS down with a clear message rather than burning CPU. The usual fix is to give the kubelet a different resolver file that lists the real upstream servers.

The cache plugin

The cache plugin remembers answers, both positive (“here is the address”) and negative (“that name does not exist”). It keeps each answer for the time it was told by the original source, capped by a maximum you set, often thirty seconds. Lower caps keep data fresher; higher caps reduce load.

Positive

Success cache

Stores real answers. Most helpful for external names, which are expensive to fetch.

Negative

Denial cache

Stores “does not exist” answers. Crucial because the search list creates many of them.

Prefetch

Refresh early

Optionally re-fetches popular names just before they expire, so users never wait for a miss.

Resilience

Serve stale

Optionally keeps serving an expired answer for a limited time if upstream is down, trading freshness for availability.

Caches outside CoreDNS

CoreDNS is not the only place answers are remembered. Applications and their runtimes have their own habits. Many do not cache at all and ask DNS for every new connection. Some, such as certain Java configurations, cache answers for a long time or even forever, ignoring the TTL, which can leave an application talking to an old address after a change. Connection pools and proxies often resolve a name once and keep using it. When “DNS changes are not picked up,” the culprit is usually one of these client-side caches, not CoreDNS.

Everyday analogy

Reception keeps sticky notes of recent answers. The staff each keep their own notebooks as well. If a person moves, reception fixes its note within 30 seconds, but a staff member with an old notebook entry keeps calling the wrong desk until they cross it out. Changing the note on the wall does not fix the notebooks.

PlaceTypical lifetimeWho controls it
Application or runtimeNone to forever, depending on language and settings.Application developers.
NodeLocal DNSCache (if used)Seconds to a few minutes.Platform team.
CoreDNS cacheOften up to 30 seconds.Corefile.
Upstream resolverThe record’s own TTL.Owner of the domain.
i
Tip

Know the DNS cache setting of the language runtimes your teams use. A short list of “how long does our Java, Go, Python and Node code cache DNS?” saves many painful debugging sessions during failovers.

10NodeLocal DNSCache: A Cache on Every Node

When one cluster-wide DNS service is not enough, the next step is to put a small cache on every node.

flowchart LR
  P["Pod"] -->|UDP to link local address| NL["NodeLocal DNS cache on the same node"]
  NL -->|hit| P
  NL -->|miss, TCP| CD["CoreDNS Pods"]
  NL -->|external names, miss| UP["Upstream resolver"]
  CD --> UP
    
Figure 4: A per-node cache sits between Pods and CoreDNS, answering repeats locally.

How it works

NodeLocal DNSCache is a small DNS cache that runs as a DaemonSet, which means one copy on every node. Each copy listens on a special local address that exists only on its own node. Pods are pointed at that address instead of the cluster-wide Service. Questions that the node-local cache has answered recently never leave the machine. Only cache misses travel on to CoreDNS, and when they do, the cache uses TCP instead of UDP.

The problems it solves

1

Fewer network hops

Cache hits are answered on the same machine, in a fraction of a millisecond, with no packet crossing the cluster network.

2

Escaping connection tracking trouble

Linux tracks every UDP flow through the Service address, and a known race in this tracking can cause lookups to hang for five seconds when two queries for the same name leave at once. The node-local cache bypasses this tracking for its traffic, and uses TCP upstream.

3

Absorbing the search-list noise

The repeated “does not exist” answers from ndots expansion are cached locally, not sent to CoreDNS over and over.

4

Protecting upstream limits

Fewer queries reach the cloud resolver, which helps when the provider limits how many packets each network interface may send.

5

Steadier CoreDNS load

CoreDNS sees mostly misses, so it needs fewer replicas for the same Pod count.

Everyday analogy

Instead of everyone on every floor calling the main reception, each floor has its own small desk with a copy of the most-used answers. Most questions are answered right there. Only unusual ones are passed up to the main reception, using a more reliable but slower phone line.

Pros of NodeLocal DNSCache

  • Much lower average and tail latency for repeated names.
  • Avoids the connection-tracking hangs on UDP.
  • Reduces CoreDNS and upstream load sharply.
  • Keeps serving cached answers if CoreDNS briefly fails.

Cons of NodeLocal DNSCache

  • One more component on every node to patch and monitor.
  • If the local cache fails, Pods on that node can lose DNS unless a fallback is in place.
  • Extra memory on every node.
  • Another layer of caching to reason about when debugging.

Production example: large clusters on cloud networks

Teams running large clusters on AWS often deploy NodeLocal DNSCache from the Kubernetes project’s manifests because the cloud’s private resolver limits how many packets a single network interface can send per second. Since every external lookup from every Pod on a node leaves through that interface, a per-node cache is a direct, practical shield. It is not part of the managed CoreDNS add-on, so you operate it yourself.

!
Watch out

Roll out NodeLocal DNSCache gradually, one node group at a time, and watch for failed lookups. Make sure you know how Pods behave if the local cache is unavailable, because the answer depends on how it was installed.

11Data Flow and Lifecycle: How DNS Follows a Changing Cluster

DNS is a snapshot of a moving target. Seeing how the snapshot is refreshed explains many odd moments during deployments.

A rolling update, as DNS sees it

1

New Pods start

They are not yet ready, so they are left out of headless answers and receive no Service traffic.

2

They become ready

Endpoint slices add their addresses. CoreDNS hears about it within moments. For ordinary Services DNS still returns the same ClusterIP.

3

Old Pods are told to stop

They are removed from endpoint slices first, then given time to finish work before being killed.

4

Headless clients may lag

A client holding the old list of addresses can still try a stopped Pod until its cached list expires. Normal Services avoid this, because kube-proxy updates its own rules separately.

This shows why ordinary Services are more forgiving than headless ones: the DNS answer never changes, and the changing part is handled by routing rules on each node. With headless Services, the client uses real Pod addresses, so every cache between CoreDNS and the client matters.

When CoreDNS itself is updated

CoreDNS Pods also come and go. During a rolling update, a Pod being removed should finish in-flight queries and stop receiving new ones. The health plugin supports a short lameduck period: for several seconds after shutdown begins, the Pod keeps answering while the rest of the cluster learns it is leaving. Without it, clients may send queries to a Pod that no longer exists, and because UDP routes are tracked on the node for a time, some packets may be lost until stale entries expire.

Where the delays come from

StepTypical delayControlled by
API server tells CoreDNS about a changeWell under a secondCluster health, API server load.
Answer remembered by CoreDNSUp to the cache cap, often 30 secondsCorefile cache and TTL settings.
Answer remembered by NodeLocal DNSCacheSeconds to minutesIts own configuration.
Answer remembered in the appNone to unlimitedLanguage runtime and code.
Corefile change takes effectAbout a minute or twoThe reload plugin interval.

Startup order and readiness

A new Pod’s first lookup happens as soon as its code starts. If CoreDNS is not ready, or the Pod has not yet learned about a Service, that first lookup can fail. Healthy applications retry with a short delay instead of giving up, and init steps in deployments sometimes wait for dependencies by name. A well-behaved cluster does not assume DNS is perfect at the first millisecond.

Everyday analogy

When a shop moves to a new address, the sign on the old door is changed immediately (the DNS update), but customers still hold old business cards (client caches). For a while, a few arrive at the wrong door. A good shop leaves a forwarding note on the old door for a few days, the way a service stays up while old Pods drain.

i
Tip

When a rollout seems to cause brief errors only for some callers, ask whether the target is a headless Service. If it is, shorten client DNS caching and make sure the old Pods keep serving for a few extra seconds before they exit.

12Performance and Scalability

CoreDNS itself is fast. The challenge is the volume and shape of the traffic sent to it, and the limits of what lies beyond it.

Where the load comes from

Multiplier

Query amplification

Search-list expansion plus separate IPv4 and IPv6 queries can turn one lookup into about ten. The cure is in the Pod’s settings, not in CoreDNS.

Pattern

New connection per request

Code that opens a fresh connection for every call asks DNS every time. Pooling connections removes most of this.

Scale

Number of Pods

More Pods means more resolvers, each sending queries. A cluster of thousands of Pods can send tens of thousands of queries per second.

Outside

Upstream limits

Cloud resolvers cap packet rates per network interface. On AWS the limit for the built-in VPC resolver is about 1,024 packets per second per interface, shared by everything on that node.

Understanding the AWS packet limit

Inside an Amazon VPC, DNS queries to the Amazon-provided resolver are limited per network interface. A node that runs a CoreDNS Pod and forwards many external lookups can reach this limit without being busy at all, because the ndots multiplication creates so many small packets. When the limit is hit, packets are dropped, and applications see random timeouts or five-second delays. The symptoms look like a flaky CoreDNS, but the problem is the interface limit. The usual remedies are spreading CoreDNS Pods over more nodes, caching on the node with NodeLocal DNSCache, lowering ndots, and using trailing dots.

Sizing CoreDNS

1

Count replicas with the cluster size

A common approach is a small helper that scales CoreDNS in proportion to the number of nodes and cores, so DNS capacity grows as the cluster does.

2

Give it enough memory

Memory depends on the number of Services and endpoints, plus the cache size. The default limits in common installers are modest, so large clusters should raise them.

3

Spread across nodes and zones

Anti-affinity rules prevent all replicas from landing on one machine, and also spread the upstream packet load.

4

Watch the cache hit ratio

A low hit ratio means the cache is too small, too short-lived, or being bypassed by unique names.

5

Load-test before you need it

Use a DNS load tool to simulate peak query rates and confirm that latency and errors stay low.

LeverEffectCost or risk
More CoreDNS replicasMore capacity, more cache copies.More memory and more API server watches.
Larger cache and longer capHigher hit ratio, lower load.Slower to reflect changes.
Lower ndots / trailing dotsRemoves most wasted queries.Needs testing of name habits.
NodeLocal DNSCacheRemoves hops, tracking issues and upstream pressure.Extra component per node.
Dedicated upstream resolversEscapes provider packet limits.You must run and secure them.
Connection reuse in appsFewer lookups per second.Needs code or library changes.
Everyday analogy

A call centre with perfectly trained staff can still collapse if every caller asks ten questions where one would do, or if the outside phone line only carries a thousand calls a second. Hiring more agents (replicas) helps, but shortening the calls (fewer queries) and adding local help desks (node caches) is cheaper.

!
Watch out

Adding replicas to fix a problem that is really caused by the upstream packet limit or by the search list can make things slightly worse, because every new replica also adds a watch on the API server and more copies of the data. Diagnose first.

13High Availability and Reliability

DNS is a dependency of almost everything. When it fails, the symptoms appear everywhere except in DNS itself.

What happens when CoreDNS is down

The first thing to understand is the pattern of failure. Connections that are already open keep working, because they use IP addresses. Lookups answered from a cache keep working until the cache entries expire. But any new lookup that misses a cache fails. So an outage starts slowly, with a trickle of errors, then grows as caches expire, and reaches full strength after a minute or so. By then, applications are failing to start, retry storms are growing, and engineers are looking at the wrong systems.

Resolver timeouts make it worse

The default resolver in most Linux systems waits about five seconds for each attempt and tries twice. A single failed lookup can therefore stall an application for ten seconds or more before returning an error, and when each name in a long search list fails in turn, the delays add up. Slow, silent hangs are the typical user experience of a DNS problem, not clean errors. Lowering the timeout and attempts in the Pod’s options can turn a long hang into a quick failure that retry logic can handle.

1

Run enough replicas

At least two, and more as the cluster grows. A single replica is a single point of failure, even for a rolling update.

2

Spread them

Use anti-affinity or topology rules so the replicas sit on different nodes and in different zones.

3

Protect them during maintenance

A disruption budget stops a node drain from removing every replica at the same time.

4

Use readiness and lameduck

The readiness check keeps traffic away until CoreDNS has loaded its data, and lameduck lets a leaving Pod finish its work.

5

Add a node-level cache

NodeLocal DNSCache can keep serving recent answers if CoreDNS has a brief problem.

6

Give it priority

Mark CoreDNS as a critical system component so it is not evicted first when a node is short of resources.

FailureWhat users seeProtection
One CoreDNS Pod crashesA few slow lookups while the Service reroutes.Multiple replicas, readiness checks.
All Pods on one node lostBrief errors from Pods that used those replicas.Spread across nodes and zones.
Upstream resolver down or throttledExternal names fail or time out; cluster names work.Multiple upstreams, caching, serve-stale.
API server unreachableExisting records keep working; changes are not picked up.CoreDNS keeps its last copy.
Bad Corefile changeDNS outage if reload is accepted; otherwise old config stays.Staging tests, version control, careful rollout.
Forwarding loopCoreDNS stops with a loop message.Correct upstream resolver file for the kubelet.
Node-local cache failsLookups from that node fail or are slow.Health checks, gradual rollout, fallback path.
Everyday analogy

If the phone book service closes, people who already know the number keep talking. But anyone who needs a new number is stuck. At first only a few notice; after a few hours of their notebooks going out of date, nearly everyone does. A spare receptionist in another room and a few handy notebooks make the difference between a hiccup and a crisis.

i
Tip

Practise failure. In a test cluster, delete one CoreDNS Pod during a load test, then delete a node, then cut the upstream. Seeing how your applications behave in each case is worth more than any document.

14Security Considerations

DNS is both a map of your cluster and a channel that almost every firewall lets through. Treat it with respect.

Network policy

Remember to allow DNS

When you apply a default-deny rule for outgoing traffic, Pods can no longer reach CoreDNS, and everything seems to break. Explicitly allow UDP and TCP port 53 to the DNS Pods, selecting them by the labels on the system namespace and the Pods.

Visibility

DNS reveals names

Any Pod can look up any Service name in any namespace. This helps attackers map your internal systems. The kubernetes plugin can be limited to selected namespaces, and network policy limits what lookups can reach.

Config

Guard the Corefile

Whoever can edit the CoreDNS ConfigMap can redirect any name for the whole cluster, for example sending a bank’s website to a fake server. Restrict write access to the system namespace tightly.

Least privilege

Small RBAC role

CoreDNS needs only to read Services, endpoints and namespaces. Do not widen its role.

Abuse

DNS tunneling

Attackers can hide stolen data inside DNS names. Logging, query-rate monitoring, and egress filtering on resolvers help spot it. Cloud features such as DNS firewalls on the provider’s resolver add a further layer.

Access

Limit who may ask

An access-control plugin can restrict which networks may query CoreDNS, useful if it is ever exposed beyond the cluster.

Trust in the answers

By default, CoreDNS does not validate the cryptographic signatures that some domains use to prove their answers are genuine. It trusts what its upstream resolvers say. Within the cluster, this trust is extended to the network: a malicious Pod with the right network position could try to forge replies. Keeping Pods apart with network policy, encrypting service-to-service traffic with certificates that verify names, and not treating DNS alone as proof of identity are the true defences.

!
Watch out

DNS names are not authentication. Seeing that a name resolves to an address proves nothing about who answers at that address. Always combine names with certificates or service identities.

Logging with care

Query logs are a powerful forensic tool, because they show which Pod looked up which name. They also reveal sensitive information, such as the names of customers or internal systems, and they can be huge. Turn logging on for a short time to investigate, or send it to a protected store with a clear retention period.

15Monitoring, Logging and Troubleshooting

CoreDNS is easy to observe if you know which numbers to read. Most DNS mysteries can be solved in a few minutes with the right ones.

Metrics worth graphing

Metric (simplified)What it tells youWorry when
coredns_dns_requests_totalQueries per second, by type and protocol.Sudden surge or sustained climb beyond capacity.
coredns_dns_responses_totalReplies by result code: success, NXDOMAIN, SERVFAIL.NXDOMAIN share is very high, or SERVFAIL appears.
coredns_dns_request_duration_secondsTime to answer.The slow tail grows.
coredns_cache_hits_total and missesHow well the cache works.Low hit ratio.
coredns_forward_requests_total and durationLoad on and speed of upstream.Upstream latency rises or errors appear.
Forward health check failuresUpstream resolvers marked unhealthy.Any sustained count.
Max concurrent rejectsQueries refused because too many were already in flight.Any non-zero value.
DNS programming latencyHow long the cluster takes to reflect a change in DNS.It rises beyond a second or two.
Pod restarts and memory useBasic health of CoreDNS Pods.Restarts, or memory near its limit.

Symptoms and likely causes

SymptomLikely causeFirst step
Every lookup fails in a namespaceNetwork policy blocks port 53.Check egress rules for DNS.
Random five-second delaysConnection-tracking race on UDP, or upstream packet drops.Consider NodeLocal DNSCache; check upstream limits.
External names slow, cluster names fineUpstream resolver issue or throttling.Test the upstream directly; check forward metrics.
Very high NXDOMAIN ratendots search expansion.Use trailing dots or lower ndots.
CoreDNS Pods restart with “loop” messageForwarding loop through the node’s local resolver.Point the kubelet at the real resolver file.
CoreDNS killed for memoryLimit too low for the number of Services, or cache too large.Raise the limit; check object counts.
Name works from one Pod, not anotherDifferent dnsPolicy, namespace or search path.Compare the two resolver files.
Old address returned after a changeCache in the application or runtime.Check runtime DNS cache settings.

A troubleshooting routine

1

Start from the failing Pod

Read its resolver file. Is the nameserver the expected address? Are the search domains and ndots what you assumed?

2

Use a debug Pod

Run a small Pod with DNS tools in the same namespace. Test a cluster name, an external name, and a name with a trailing dot.

3

Split the path in two

Query the Service address, then query a CoreDNS Pod’s own address directly. If the Pod works and the Service does not, the problem is routing (kube-proxy, network policy), not CoreDNS.

4

Check the CoreDNS side

Look at Pod status, logs, and the Service’s endpoints. Confirm that replicas are ready and spread out.

5

Check upstream

Query the upstream resolver directly from a node. If it is slow there, no change in the cluster will help.

6

Turn on logging briefly

Enable query logging for a short time to see exactly what is being asked, then switch it off.

i
Tip

Alert on three things only to start: a rising SERVFAIL or timeout rate, the 99th percentile response time, and CoreDNS Pods restarting. Everything else can sit on a dashboard.

16Design Patterns, Anti-Patterns and Best Practices

Operators of large clusters keep repeating the same advice. Here it is, in one place.

Patterns worth copying

Pattern

Short names inside, full names outside

Use short Service names for same-namespace calls, and fully qualified names with a trailing dot for external hosts.

Pattern

Cache close to the Pod

Use NodeLocal DNSCache in busy clusters so most answers never cross the network.

Pattern

Stable names for stateful systems

Use StatefulSets with headless Services, so members find each other by permanent names.

Pattern

Scale with the cluster

Let CoreDNS replica count and memory grow automatically with nodes and Services.

Pattern

Reuse connections

Pool and reuse connections so DNS is a rare event, not a per-request cost.

Pattern

Config in version control

Keep the Corefile in a repository, review changes, and roll out gradually.

Traps to avoid

ANTI-PATTERN 01Avoid
What people do

They run a single CoreDNS replica to save a few megabytes of memory.

Why it hurts

Every Pod restart, node maintenance or crash becomes a cluster-wide DNS outage.

Do this instead

Run at least two replicas on different nodes, with a disruption budget, and scale with the cluster.

ANTI-PATTERN 02Avoid
What people do

They leave query logging switched on permanently in production.

Why it hurts

Each query writes a line. Log volume grows into millions of lines, slows CoreDNS, fills disks, and raises storage costs and privacy exposure.

Do this instead

Rely on metrics day to day, and turn on logging only for short investigations.

ANTI-PATTERN 03Avoid
What people do

They hard-code Pod IP addresses, or resolve a name once at start-up and keep it for the life of the process.

Why it hurts

Pod addresses change constantly. After a restart or failover, the program talks to an address that no longer belongs to the service it wants.

Do this instead

Use Service names and let the runtime re-resolve regularly, respecting TTLs.

ANTI-PATTERN 04Avoid
What people do

They add a pile of Corefile experiments by hand in production, with no tests or reviews.

Why it hurts

One typo can silently change how every name is resolved for every application.

Do this instead

Test in a non-production cluster, review the change, and roll it out gradually while watching error rates.

Best practices at a glance

1

Measure NXDOMAIN share

It tells you at once whether the search list is wasting capacity.

2

Allow DNS in every network policy

Make it part of the standard template for default-deny rules.

3

Know your upstream limits

Learn the packet and rate limits of your cloud resolver and design around them.

4

Document runtime DNS behaviour

Keep a short guide to how each language your teams use caches and retries DNS.

5

Keep CoreDNS up to date

Newer versions fix bugs and improve performance; managed add-ons make this easier.

Common mistakes and quick fixes

MistakeWhat you seeFix
Default-deny policy without a DNS ruleEvery Pod suddenly cannot resolve names.Allow port 53 (UDP and TCP) to the DNS Pods.
Host-network Pod with default policyService names do not resolve.Use ClusterFirstWithHostNet.
Assuming Corefile order sets plugin orderChanges have no effect.Learn the fixed plugin order.
Very high ttl and cache for headless ServicesClients use stale Pod addresses.Use shorter values for headless data.
Too many search domainsWarnings, truncated lists, strange lookups.Keep to six or fewer and 256 characters.
Using only UDP in firewallsLarge answers fail.Allow TCP port 53 too.
Treating ExternalName as a proxyCertificate or Host header errors.Remember it is only a DNS alias.

Advantages of cluster DNS

  • Stable names for a world of changing addresses.
  • Works the same in every environment.
  • Highly customizable with small plugins.
  • Free, built in, and well understood.

Disadvantages and trade-offs

  • Everything depends on it, so outages are wide.
  • Default search settings multiply traffic.
  • Several cache layers make changes slow to appear.
  • Needs sizing, monitoring and care at scale.

17Real-World and Industry Examples

The same few patterns show up in every large environment. Here are the places you are most likely to meet them.

Amazon EKS: the managed add-on and the VPC resolver

On EKS, CoreDNS runs as a managed add-on, and upstream queries go to the VPC’s built-in resolver. That resolver’s per-interface packet limit is one of the most common hidden causes of intermittent DNS timeouts in busy clusters. Teams typically fix it with NodeLocal DNSCache, lower ndots values, and spreading CoreDNS across nodes.

Google GKE: kube-dns by default, with options

GKE has long offered cluster DNS through kube-dns, and also supports NodeLocal DNSCache and a Cloud DNS option for cluster scope. This shows that the interface (the Service name, the search domains, the record formats) stays the same while the engine behind it can change.

Databases and brokers on StatefulSets

Systems such as Kafka, Cassandra and etcd use headless Services so that each member has a stable DNS name. Their configuration lists those names, and the cluster DNS keeps them pointed at the right Pods through restarts and rescheduling.

ExternalDNS: the other DNS

A common point of confusion: a tool called ExternalDNS publishes the hostnames of your Ingresses and Services into public DNS zones, such as those in Amazon Route 53. It is completely separate from CoreDNS. CoreDNS answers questions inside the cluster; ExternalDNS makes your services findable from outside.

Service meshes and local DNS helpers

Some service meshes place a small DNS helper next to each application to answer certain names locally, reducing the load on cluster DNS and allowing special names. Like NodeLocal DNSCache, this uses the same idea: answer close to the caller, and send only the hard questions upstream.

Most DNS problems in Kubernetes are not DNS problems at all; they are traffic-shape problems, cache problems, or limit problems wearing a DNS costume.

A typical journey at a growing company

A team starts with the default CoreDNS and two replicas. As the cluster grows from fifty to five hundred nodes, intermittent five-second delays appear. After weeks of searching, they discover that applications are sending several wasted queries per lookup through the search list, and that the cloud resolver is dropping packets on busy nodes. They add trailing dots to external hostnames, set ndots to a lower value for chatty workloads, deploy a node-local cache, and let CoreDNS scale with the node count. Metrics for NXDOMAIN rate and upstream latency go on a dashboard, with alerts for errors. The delays disappear, and DNS becomes quiet and boring, which is exactly what a good phone book should be.

18Frequently Asked Questions

Q1Why is the DNS Service still called kube-dns if CoreDNS is running?
For backward compatibility. Many tools look for a Service with that name, so it was kept when CoreDNS replaced the old implementation.
Q2What is the full DNS name of a Service?
The Service name, then the namespace, then svc, then the cluster domain, which is cluster.local by default. For example, orders in the shop namespace is orders.shop.svc.cluster.local.
Q3Why do external lookups from Pods take so many queries?
Because of the search list and the default ndots value of five. Names with fewer than five dots try every search suffix first. Adding a trailing dot or lowering ndots avoids this.
Q4Can a Pod in one namespace resolve Services in another?
Yes, by using service.namespace or the full name. Namespaces organize names; they do not block lookups. Use network policy for isolation.
Q5What is the difference between a headless Service and a normal one in DNS?
A normal Service returns a single virtual address. A headless Service returns the addresses of the ready Pods behind it, so clients see and can choose among the real members.
Q6How do I send one domain to my company’s DNS servers?
Add a server block to the Corefile for that domain and forward it to the corporate servers. Everything else continues to use the usual path.
Q7Does the order of lines in the Corefile matter?
Not for the order in which plugins run. That order is fixed when CoreDNS is built. The file decides which plugins are active and how they are configured.
Q8How long does it take for a new Service to be resolvable?
Usually within a second or so, since CoreDNS watches the API server. A cached “does not exist” answer from an earlier lookup can delay it for the cache duration.
Q9What causes random five-second DNS delays?
Commonly a race in the Linux connection-tracking system when two queries for the same name leave at once over UDP, or packet loss at an upstream limit. NodeLocal DNSCache, fewer wasted queries and fixed upstream limits are the usual cures.
Q10Do I need NodeLocal DNSCache?
Not in small or quiet clusters. It becomes valuable in large or busy clusters, or whenever you see timeouts, high NXDOMAIN rates or upstream packet limits.
Q11Why do my Pods not see a DNS change?
Almost always a cache in the application or its language runtime, or a long TTL somewhere along the path. CoreDNS itself updates quickly.
Q12How do I check which DNS settings a Pod has?
Look at the contents of its /etc/resolv.conf from inside the Pod. It shows the nameserver, search list and options. Also check the Pod’s DNS policy and any extra DNS configuration.
Q13How is ExternalDNS different from CoreDNS?
CoreDNS serves names inside the cluster to your Pods. ExternalDNS publishes names of your Services and Ingresses to public or private DNS zones outside the cluster. They solve different problems and often run together.

19Summary and Key Takeaways

Cluster DNS turns the shifting world of Pods into stable names that applications can rely on. CoreDNS does this with a chain of small plugins: the kubernetes plugin answers cluster names from a live in-memory picture of Services and endpoint slices, the cache remembers answers, and the forward plugin asks upstream resolvers about everything else. Most of the cost and most of the confusion come from how Pods ask questions, especially the search list and ndots setting, and from layers of caching and external limits. Understanding those lets you keep DNS fast, reliable and quiet.

Key Takeaways

  • Names beat addresses. Pods are temporary, so Services get stable DNS names of the form service.namespace.svc.cluster.local, served by CoreDNS behind the kube-dns Service.
  • Everything in CoreDNS is a plugin. The kubernetes, cache and forward plugins do the main work, and their order is fixed by the build, not by the Corefile.
  • The Pod’s resolver file shapes the traffic. Search domains and ndots of five can turn one external lookup into about ten queries. Trailing dots, lower ndots and node-local caching fix this.
  • Headless Services expose real Pod addresses. They support StatefulSets and clustered systems, but make caching and TTLs matter much more.
  • Many caches, many delays. CoreDNS, NodeLocal DNSCache and application runtimes each remember answers, so changes take time to appear everywhere.
  • Mind the limits beyond the cluster. Upstream resolvers, such as the VPC resolver on AWS, have packet limits that can cause timeouts that look like CoreDNS faults.
  • Treat DNS as critical infrastructure. Run several spread-out replicas, scale with the cluster, allow port 53 in network policies, guard the Corefile, and watch response codes, latency and cache hit ratio.