Tech
Understanding Kubernetes Networking: Services, Ingress, and DNS
A practical guide to how Kubernetes handles traffic, covering the differences between Service types, the role of Ingress Controllers, and how CoreDNS enables internal service discovery.
June 2026 · 6 min read · 1 views · 0 hearts
Advertisement
Kubernetes networking can feel like a black box—especially when you’re trying to route external traffic to your pods, or get services talking to each other inside the cluster. You’ve probably heard of Services, Ingress Controllers, and maybe something about CoreDNS, but how do they actually fit together? Let’s crack that open with a clear, practical look at what each piece does and why you need them.
The Three Networking Layers You Can’t Ignore
Think of Kubernetes networking as three concentric circles:
- Pod-to-Pod communication (flat network, every pod gets its own IP)
- Service-to-Pod communication (stable endpoint, load balancing)
- External-to-Service communication (Ingress or LoadBalancer)
The magic is that you rarely need to worry about pod IPs—Kubernetes handles that. But understanding the mechanisms between those layers is where real control lives.
Services: The Stable Anchor
A Service in Kubernetes is essentially a fixed IP and DNS name that sits in front of a set of pods. Pods come and go (crashes, scaling, rolling updates), but the Service stays constant. There are four types, but the two you’ll use most are:
- ClusterIP: Internal only. Great for backend services that don’t need outside access.
- NodePort: Exposes the service on a static port across all cluster nodes. Useful for dev or testing, but not production-grade.
- LoadBalancer: Creates an external load balancer (like an AWS ELB or GCP LB). Works well for a single service, but can get expensive if you have many.
- ExternalName: Maps to an external DNS name—mostly for migrating legacy systems.
What actually happens under the hood? Each Service gets a virtual IP (cluster IP) and listens on a port. kube-proxy on each node maintains iptables or IPVS rules that redirect traffic to the correct pod. That’s the load balancing—simple, fast, and stateless.
Ingress Controllers: The Smart Front Door
Services alone handle traffic to a single application. But what if you want to route traffic by hostname (e.g., api.example.com → Service A, web.example.com → Service B)? Or handle path-based routing like /api/* to one backend and /static/* to another? That’s where Ingress comes in.
An Ingress resource is just a set of rules—it defines how traffic should be routed. But it’s not enough on its own. You need an Ingress Controller running in the cluster to actually implement those rules. Popular choices include:
- NGINX Ingress Controller (most common, battle-tested)
- Traefik (great for dynamic environments)
- HAProxy (performance-oriented)
- AWS ALB Ingress Controller (for native AWS integration)
The flow works like this:
User → DNS → Ingress Controller (pod/service) → Service → Pod
The Ingress Controller itself runs as a pod (often behind a LoadBalancer Service) and listens on ports 80 and 443. It watches the cluster for Ingress resources, then automatically updates its configuration (e.g., NGINX config files) and reloads. No manual restart needed.
Real-world gotcha: TLS termination
Ingress Controllers can handle SSL certificates—just reference a TLS secret in your Ingress YAML. This offloads the complexity from your application pods. But make sure your secret is in the same namespace as the Ingress, or you’ll hit a cryptic error.
Service Discovery: How Pods Find Each Other
Once your pods need to talk to each other (say, a frontend calling a backend), they need a way to discover the backend’s Service IP. Kubernetes provides DNS-based service discovery by default, via CoreDNS (or kube-dns in older clusters).
Every Service gets a DNS name like my-service.namespace.svc.cluster.local. A pod in the same namespace can just use my-service. Cross-namespace? Use my-service.other-ns.
What’s less obvious is how that DNS resolution actually works from inside a pod:
- Kubernetes injects a DNS resolver configuration (
/etc/resolv.conf) into every pod, pointing to CoreDNS pod IPs. - CoreDNS watches the cluster for Services and endpoints.
- When your app does a DNS lookup, CoreDNS returns the Service’s cluster IP.
kube-proxythen handles routing that traffic to a healthy pod.
Putting It All Together: End-to-End Flow
Here’s a concrete walkthrough for an e-commerce app:
- External user hits
shop.example.com. - DNS resolves to your cloud load balancer (e.g., AWS NLB).
- That NLB forwards traffic to all nodes in the cluster on port 443.
- The NGINX Ingress Controller (running as a DaemonSet or Deployment) picks it up, matches the hostname, and routes to the
frontendService. - The
frontendService (ClusterIP) load-balances to one of threefrontendpods. - That pod needs product data. It calls
product-service.default.svc.cluster.local. - CoreDNS returns the cluster IP of the
product-serviceService. - kube-proxy sends that request to a healthy
product-backendpod.
All of this happens without the developer hardcoding any IPs—it’s all dynamic.
Common Pitfalls (and How to Avoid Them)
- Ingress Controller not running: An Ingress resource with no controller does nothing. Check that you actually have a controller pod running.
- Namespace mismatch: Services and Ingress resources must reference correct namespaces. A common error is putting TLS secrets in a different namespace.
- Headless Services for stateful apps: If you use a StatefulSet (e.g., databases), use a headless Service (
clusterIP: None). It returns pod IPs directly instead of a single cluster IP, allowing stateful discovery via DNS. - NodePort port conflicts: If you run many NodePort Services, you might hit port limits. Prefer Ingress or LoadBalancer for production.
- DNS caching: Some applications aggressively cache DNS. If a pod restarts, the old IP might be cached. Set low TTLs or use headless services with client-side load balancing.
Choosing the Right Strategy
There’s no one-size-fits-all. For a small internal tool, a simple ClusterIP Service might be all you need. For a multi-tenant SaaS, you’ll want an Ingress Controller with path-based routing and TLS termination. For microservices requiring service mesh, tools like Istio or Linkerd add extra layers on top of this foundation.
The key takeaway: Kubernetes networking isn’t magic—it’s a stack of well-defined components. Services provide stability, Ingress Controllers give you smart routing, and DNS-based service discovery keeps everything decoupled. Master those three, and you’ll rarely get lost in the network weeds again.
Advertisement
Comments
Questions, corrections, and tips stay visible for everyone reading this page.
Join the discussion
No comments yet
Be the first to leave a note — it helps the next reader.