Understanding Service DNS in Kubernetes: A Practical Guide
Learn how Kubernetes uses CoreDNS for service discovery. Master internal DNS resolution to replace hardcoded IPs with stable, reliable service names.

Previously in this course, we explored the role of Services and how to create a ClusterIP Service to provide stable networking. While those services provide a stable IP, managing IPs manually is a recipe for failure. In this lesson, we will look at how Kubernetes automates discovery using DNS, allowing your pods to talk to each other using simple, human-readable names.
How Kubernetes Resolves Service Names
In a dynamic environment, Pod IPs change constantly as they are created and destroyed. You cannot rely on them. Kubernetes solves this by running an internal DNS server, CoreDNS, which is itself a set of pods running in your cluster.
When you create a Service, the Kubernetes API server creates a DNS entry for it in CoreDNS. Because CoreDNS is configured as the upstream DNS resolver for every pod in the cluster, your applications don't need to know where a service lives—they just need to know its name.
The standard format for a service name is:
service-name.namespace.svc.cluster.local
- service-name: The name you defined in your Service manifest.
- namespace: The namespace where the service resides.
- svc.cluster.local: The cluster domain suffix.
If your pod is in the same namespace as the service, you can often just use service-name. However, using the Fully Qualified Domain Name (FQDN) is a best practice for cross-namespace communication.
CoreDNS: The Engine of Discovery
CoreDNS acts as the phonebook of your cluster. When a process inside a container attempts to connect to a service name, the request hits the CoreDNS pod. CoreDNS looks up the service's current virtual IP (ClusterIP) and returns it to the requester.
Flow diagram: Pod A -- "DNS Query: my-svc" → CoreDNS; B -- "Returns ClusterIP: 10.96.0.5" → Pod A; A -- "Traffic to 10.96.0.5" → Service my-svc; C -- "Load Balances" → Pod B
Worked Example: Testing DNS Resolution
To verify this, we will deploy a simple "busybox" container to act as our testing client and a standard Nginx service.
- Create the target service:
Assuming you have an Nginx deployment named
nginx-app, create a service manifestnginx-svc.yaml:
YAMLapiVersion: v1 kind: Service metadata: name: nginx-service spec: selector: app: nginx ports: - port: 80
- Deploy the test pod: Run an interactive busybox shell to test the connection:
Bashkubectl run dns-test --rm -it --image=busybox -- sh
- Perform the lookup:
Once inside the shell, use the
nslookupcommand to resolve the service name:
Bashnslookup nginx-service
You should see an output showing the address of nginx-service.default.svc.cluster.local pointing to your ClusterIP.
Hands-on Exercise
- Create a second namespace called
testing. - Move your
nginx-serviceinto that namespace (or create a new one there). - From your
dns-testpod in thedefaultnamespace, attempt to resolve the service using the full FQDN:nslookup nginx-service.testing.svc.cluster.local. - Verify that the resolution succeeds.
Common Pitfalls
- Namespace Isolation: A common mistake is trying to reach a service in another namespace using only its short name. Always use the FQDN when crossing namespace boundaries.
- Firewalls and Network Policies: If DNS resolution works (the IP is returned) but the connection fails, the issue is likely a NetworkPolicy blocking traffic, not a DNS issue.
- CoreDNS Issues: If
nslookupreturns a timeout or "server failure," check the status of your CoreDNS pods:kubectl get pods -n kube-system -l k8s-app=kube-dns.
FAQ
Does CoreDNS handle external domains? Yes. If a query doesn't match an internal service, CoreDNS forwards the request to your cloud provider's DNS (like AWS Route53 or Google Cloud DNS).
Can I use custom names for services?
The DNS name is strictly bound to the metadata.name field of your Service resource.
Does DNS work for Pods directly?
Yes, but you must create a "Headless Service" (setting clusterIP: None in the manifest). Otherwise, DNS only points to the stable Service IP, not individual Pod IPs.
Recap
We've moved beyond hardcoded IPs by leveraging CoreDNS. By using service names like my-service.default.svc.cluster.local, your applications remain decoupled from the volatile nature of Pod lifecycles. This is a foundational step toward building resilient, scalable systems that behave predictably in production.
Up next: We will look at how to manage Environment-Specific Configuration to ensure our manifests are portable across dev, staging, and production.


