Kubernetes Request Flow: How Traffic Reaches Your Pod
You deployed your app to Kubernetes and opened the URL — but what actually happens between the browser and your container? A request crosses DNS, a cloud load balancer, an Ingress controller, a Service, EndpointSlices, kube-proxy, and finally lands in a Pod where your application code runs.
Understanding this path is essential for debugging 502 errors, tuning health checks, and explaining system design in interviews. This article walks through all ten hops — from the user typing a URL to the response traveling back — with the networking objects that make each step possible.
User, DNS, and Load Balancer
The journey starts when a user opens a URL like `https://app.example.com`. The browser does not know your cluster — it asks public DNS to resolve the hostname. DNS returns the external IP of your cloud load balancer (AWS NLB/ALB, GCP Load Balancer, Azure LB) or the IP exposed by your Ingress controller.
The load balancer sits at the cluster edge. It terminates TLS (or passes it through), accepts TCP/HTTP traffic from the internet, and forwards it into the cluster network. Without this layer, Pod IPs would be unreachable from outside — they live on private cluster networks that are not routable on the public internet.
Quick reference
- Step 1: user sends HTTP request to a public hostname.
- Step 2: DNS resolves domain → external load balancer IP.
- Step 3: load balancer receives traffic and forwards into the cluster.
- Use health checks on the LB so unhealthy nodes are removed.
- TLS can terminate at LB, Ingress, or both (double encryption).
- Cloud LB type matters: L4 (TCP) vs L7 (HTTP routing).
Remember this
DNS points users at the load balancer — the front door into your Kubernetes cluster.
Ingress, Gateway, and Service
Inside the cluster, Ingress (or the newer Gateway API) performs HTTP/HTTPS routing. It reads rules like "host = app.example.com, path = /api → backend-service" and forwards the request to the correct internal Service. Ingress controllers (NGINX, Traefik, AWS ALB Ingress Controller) watch Ingress resources and configure themselves dynamically.
A Service gives your app a stable virtual IP and DNS name (`backend-service.production.svc.cluster.local`) even though Pod IPs change constantly. Services do not run code — they are a routing abstraction. ClusterIP Services are internal-only; LoadBalancer and NodePort types expose Services externally (often via cloud LB integration).
Quick reference
- Step 4: Ingress/Gateway routes by hostname and URL path.
- Step 5: Service provides stable endpoint — hides Pod churn.
- Ingress: mature, HTTP-focused — most clusters use it today.
- Gateway API: successor with richer L4/L7 routing models.
- ClusterIP: default internal Service type.
- Internal DNS: service-name.namespace.svc.cluster.local.
Remember this
Ingress picks the right Service; the Service is the stable name your app is known by inside the cluster.
EndpointSlices and kube-proxy
EndpointSlices (replacing the older Endpoints object) track which Pod IPs and ports are ready to receive traffic for a Service. When a Pod passes its readiness probe, it appears in the EndpointSlice; when it crashes or fails health checks, it is removed. This is how Kubernetes knows which backends are actually healthy.
kube-proxy runs on every node and programs network rules (iptables, IPVS, or eBPF) so traffic destined for a Service VIP is forwarded to a healthy Pod IP. The selection is typically round-robin or random across ready endpoints. If all Pods are unhealthy, the Service has no endpoints and clients see connection failures or 503 responses.
Quick reference
- Step 6: EndpointSlice lists ready Pod IP:port pairs.
- Step 7: kube-proxy forwards Service traffic to a Pod.
- Readiness probes control EndpointSlice membership.
- Liveness probes restart crashed containers.
- No ready endpoints → 503 / connection refused.
- kube-proxy modes: iptables (default), IPVS, or eBPF (Cilium).
Remember this
EndpointSlices tell kube-proxy which Pods are healthy; kube-proxy does the actual packet forwarding.
Pod, Container, and Response
The request reaches a Pod — the smallest deployable unit in Kubernetes, usually one or more containers sharing a network namespace. Traffic arrives on the Pod IP at the container port defined in your Deployment spec (e.g. port 8080).
The container runs your application process. It handles the HTTP request — parse headers, query a database, call another Service, build a response. When done, the response travels back along the same path in reverse: container → Pod network → kube-proxy → Service → Ingress → load balancer → internet → user browser.
Quick reference
- Step 8: request arrives at selected Pod via cluster network.
- Step 9: application container processes the request.
- Step 10: response returns User ← LB ← Ingress ← Service ← Pod.
- Pod IP is ephemeral — never hardcode it in clients.
- Sidecar containers in the same Pod share localhost networking.
- NetworkPolicies can restrict which Pods may talk to each other.
Remember this
Pods are ephemeral; Services and Ingress give the outside world a stable way to reach them.
Important Notes for Production
Several details catch teams off guard in real clusters. Services hide changing Pod IPs — always call other workloads by Service DNS, never by Pod IP. Ingress handles external HTTP routing; internal service-to-service calls use ClusterIP DNS directly, skipping Ingress entirely.
The internal DNS pattern is `service-name.namespace.svc.cluster.local` — for example `backend-service.production.svc.cluster.local`. Short names like `backend-service` work within the same namespace. Gateway API is gradually replacing Ingress for advanced routing (header-based rules, traffic splitting, TLS management), but the conceptual flow remains the same.
When debugging, trace the path: can DNS resolve? Does the LB health check pass? Does Ingress have the right host rule? Does the Service have endpoints (`kubectl get endpointslices`)? Is the Pod ready?
Quick reference
- Never call Pod IPs directly — use Service DNS.
- External traffic: User → LB → Ingress → Service → Pod.
- Internal traffic: Pod → Service DNS → Pod (skips Ingress).
- kubectl get endpointslices -n <ns> — see ready backends.
- 502 often means Ingress cannot reach Service or no endpoints.
- Gateway API: modern replacement for Ingress routing.
Remember this
Debug the chain top-down: DNS → LB → Ingress rules → Service endpoints → Pod readiness.
A Kubernetes request is not magic — it is a chain of well-defined networking layers. DNS finds the load balancer, Ingress routes HTTP to the right Service, EndpointSlices track healthy Pods, kube-proxy forwards packets, and your container finally handles the request. Learn this path once and you can diagnose production outages in minutes instead of hours. The response simply unwinds the same chain on the way back to the user.
Related Articles
Explore this topic