CoursesKubernetes fundamentalsFinding things by name

Finding things by name

Cluster DNS, simply.

Beginner8 min · lesson 18 of 24
In plain terms
Cluster DNS is the office phone book: you look up a name (“payments”) and get the number back. Your app talks to names, never to memorized IP addresses.

Your phone doesn't ask you to memorize numbers. You pick a name out of your contacts, tap it, and the call goes through. If that person switches to a new number, you update it in one place and everything keeps working. A Kubernetes cluster hands your apps the same convenience. A cluster is just the group of machines Kubernetes runs your apps across, and the feature that lets those apps find each other by name is called cluster DNS. DNS is short for Domain Name System: the service that turns a friendly name into the numeric address a computer actually dials.

Pods don't stay put, and that's the whole reason names beat numbers. Your app runs inside Pods, and a Pod is the smallest thing Kubernetes runs, roughly one live copy of your app. Pods get replaced all the time, and every fresh one comes up with a brand-new IP address, the numeric network address like 10.96.45.12 that machines use to reach each other. If your frontend had memorized a Pod's number, it would break the second that Pod was swapped out. So you don't point apps at Pods. You point them at a Service, which is a steady name and address parked in front of a group of Pods. You reach the Service by its name, and that name never changes. CoreDNS, a small program Kubernetes runs as the cluster's always-current phone book, quietly turns each name into the right address for you.

The names follow a pattern that's easy to guess once you've seen it. Say you have a Service named db living in a namespace called data. A namespace is just a named area inside the cluster that keeps one team's things separate from another's, a bit like folders on a shared drive. From an app in that same namespace, you call the Service by its short name: db. From an app in a different namespace, you tack the namespace on the end: db.data. The full, spelled-out version is db.data.svc.cluster.local. All three names point at the same Service, and you'll type the short one most days.

Set up a Service to find

Let's make this real instead of theoretical. The namespace called data doesn't exist yet, and you can't drop a Service into a namespace that isn't there, so you make it first. A namespace, remember, is that named area that keeps one team's things apart from another's.

terminal
kubectl create namespace data
output
namespace/data created

Now you need a Service worth looking up. Below is a complete file you can save and apply exactly as it is. It creates a Service named db in the data namespace that sends traffic to any Pod wearing the label app: db. A label is just a small key-value tag you stick on Pods so a Service knows which ones belong to it. You won't create any Pods with that label here, and that's fine. A Service gets its name and address the moment it exists, so DNS can answer for it even before a single Pod shows up.

db-service.yaml
apiVersion: v1
kind: Service
metadata:
name: db
namespace: data
spec:
selector:
app: db
ports:
- port: 5432
targetPort: 5432
terminal
kubectl apply -f db-service.yaml
output
service/db created

Now ask the cluster for that Service's current address. kubectl is the command-line tool you use to talk to the cluster, and the -n flag tells it which namespace to look in.

terminal
kubectl get svc db -n data
output
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
db ClusterIP 10.96.45.12 <none> 5432/TCP 12s

That CLUSTER-IP, 10.96.45.12, is the number a caller would otherwise have to know. You won't type it anywhere. The name db carries it for you, and the number is free to change without you ever noticing.

Look the name up

You can watch DNS do its job with one command. This spins up a tiny throwaway Pod, runs a name lookup inside the cluster, and deletes itself the moment it finishes. Because you don't pass -n, the Pod lands in the default namespace, so you'll reach db by its cross-namespace name, db.data.

terminal
kubectl run dnstest --rm -it --image=busybox:1.36 --restart=Never -- nslookup db.data
output
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: db.data.svc.cluster.local
Address: 10.96.45.12
pod "dnstest" deleted

The lookup came back with the full name db.data.svc.cluster.local and the address 10.96.45.12, the exact number you saw a moment ago. That Server line, 10.96.0.10, is CoreDNS itself answering. In your app's config, the database host is simply db.data. No IP addresses live in your files, and there is nothing to edit when Pods come and go underneath.

Now watch it fail

Beginners hit this one constantly, so it's worth seeing on purpose. The throwaway Pod is in the default namespace, not data. Ask it for the bare short name db, and there is nothing for CoreDNS to match, because a short name only means something inside the Service's own namespace.

terminal
kubectl run dnstest --rm -it --image=busybox:1.36 --restart=Never -- nslookup db
output
Server: 10.96.0.10
Address: 10.96.0.10:53
*** Can't find db: No answer
pod "dnstest" deleted
pod default/dnstest terminated (Error)

Read what it's telling you. CoreDNS answered on the first two lines, so DNS is healthy; it simply had no record for db from where you asked. The last line, terminated (Error), is just nslookup exiting non-zero because the lookup came up empty, not a cluster fault. The fix is the one you already ran: add the namespace and ask for db.data (or the full db.data.svc.cluster.local), and the answer comes straight back. This single mistake, a short name used from the wrong namespace, is behind a large share of 'my app can't reach the database' tickets.

How a name becomes a real address
1your app calls anamehost: db.data2CoreDNS looks itupname to Service address3the Serviceforwards onto its healthy Pods4the name outlivesthe churnPods and IPs change, the name…
You only ever write the name. Everything to the right of it can change freely, and your config never has to.

Writing your config against names instead of numbers is what makes an app easy to move and hard to break. Pod addresses shift constantly, and even a Service's address can change if it gets recreated, but the names stay put. Your config keeps working while the cluster reshuffles beneath it. The same file that says db.data runs unchanged in your test setup, in staging, and in production, because the naming pattern is identical in every cluster. And because almost everything finds its dependencies through DNS, a broken cluster DNS makes many apps fail at once and can look like a giant mysterious outage when it's really one thing. Seasoned operators check DNS first whenever a pile of unrelated things breaks together, and you'll practice that in the troubleshooting lessons.

Cluster DNS (CoreDNS) lets pods find Services by name: short names inside a namespace, FQDNs across namespaces. Prefer DNS names in config maps over IPs. When DNS breaks, everything looks like an app outage.

Debug with nslookup from a busybox pod toward service.namespace.svc.cluster.local. If DNS fails but ClusterIP curl works, you have a DNS/path problem instead of a Service selector problem.

In production, watch CoreDNS replicas and latency. A starved CoreDNS is a cluster-wide incident waiting to happen.

Try this

From a debug pod, resolve a Service short name and FQDN, then wget the Service to prove name → VIP → pod.

terminal
$ kubectl create deployment svcname --image=nginx:1.27 --replicas=1
deployment.apps/svcname created
$ kubectl expose deployment svcname --port=80
service/svcname exposed
$ kubectl run dnsbox --image=busybox:1.36 --restart=Never --command -- sleep 300
pod/dnsbox created
$ kubectl exec dnsbox -- nslookup svcname
Server: 10.96.0.10
Name: svcname.default.svc.cluster.local
Address: 10.96.88.21
$ kubectl exec dnsbox -- nslookup svcname.default.svc.cluster.local
Name: svcname.default.svc.cluster.local
Address: 10.96.88.21
$ kubectl exec dnsbox -- wget -qO- http://svcname | Select-String nginx | Select-Object -First 1
Welcome to nginx!
$ kubectl delete pod dnsbox; kubectl delete svc svcname; kubectl delete deployment svcname
pod "dnsbox" deleted
service "svcname" deleted
deployment.apps "svcname" deleted

Takeaway

Use Service DNS names, not pod IPs. Verify with nslookup from a debug pod, and treat CoreDNS health as tier-0 infrastructure for the whole cluster.

The short name only works in its own namespace
Calling a Service by its bare name, like db, only resolves from inside the same namespace. If your app runs in the web namespace and the database Service lives in data, plain db won't be found and you'll get a 'not found' error like the one above. Add the namespace and use db.data instead. When a connection works within a namespace but fails across one, this is almost always the reason.
Quick check
01Your web app runs in the namespace web and needs to reach a Service named db that lives in the namespace data. What host should its config use?
Incorrect — The bare short name only resolves from inside the same namespace. Your app is in web, so plain db won't be found, and a lookup returns 'Can't find db: No answer'.
Correct — From another namespace you add the namespace on the end, so db.data resolves to the db Service over in the data namespace, and it keeps working as Pods and IPs change.
Incorrect — That number can change if the Service is recreated, and hard-coding it throws away the entire point of names. Use the name.
Incorrect — The order is name first, then namespace: db.data, not data.db.
02The lesson says seasoned operators check cluster DNS first when a pile of unrelated apps break at the same time. Why?
Incorrect — DNS resolves names to addresses; it does not hold any application data.
Incorrect — CoreDNS only resolves names; Services route traffic independently of it.
Correct — because name lookups are the shared dependency, a single DNS fault surfaces as widespread, unrelated-looking failures.
Incorrect — A DNS outage breaks name resolution; it does not crash the nodes themselves.
03You apply the db Service in namespace data but create no Pods carrying the label app: db. From another Pod in namespace data you run nslookup db. What comes back?
Correct — DNS resolves a Service as soon as it is created, independent of whether any Pods back it yet.
Incorrect — DNS answers for the Service regardless of how many Pods sit behind it.
Incorrect — The lookup returns the queried Service's address, not the DNS server's own.
Incorrect — The Service resolves immediately; readiness of backing Pods only affects real traffic, not the name lookup.

Related