Skip to main content
Here’s a common problem every Kubernetes platform engineer encounters: Pods are ephemeral. They are created and destroyed frequently, and each pod gets a new IP address when recreated. If clients try to communicate using pod IPs directly, connectivity breaks when pods restart. Services solve this by providing a stable network endpoint and load-balancing to pods.
A presentation slide with the word "Demo" on the left and a blue curved panel on the right reading "Traffic Flow with Services and Ingress." The slide also shows a small "© Copyright KodeKloud" at the bottom left.
In this demo we will:
  • Reproduce pod churn and observe changing pod IPs.
  • Expose the app inside the cluster using a ClusterIP Service.
  • Expose it externally with a NodePort.
  • Add an Ingress (with an NGINX ingress controller) to demonstrate path-based routing to multiple backends.
Prerequisites and references:

Create a deployment and observe pod churn

Create a Deployment named web using the NGINX image with three replicas, then inspect the pods:
Now delete one pod and watch a new pod get created with a different IP:
Because the Deployment controller replaces deleted pods, the new pod has a different IP (172.17.0.9). Any client addressing the old pod IP would lose connectivity — which is why we use Services as stable access points to pods.

Expose the Deployment as a ClusterIP Service

Expose the web deployment as a ClusterIP Service (the default type) named web-svc:
Describe the service to see how it maps to pods:
Verify the pods have the label used by the Service selector:
ClusterIP services are reachable only from inside the cluster. To access the app externally, use NodePort or an Ingress.

Expose the app externally with NodePort

Create a NodePort Service named web-nodeport:
On a single-node cluster you can curl localhost with the assigned NodePort:
<NodePort has limitations — use Ingress for richer routing and TLS.>
NodePort opens high-numbered ports (typically in the 30000–32767 range) on every node. It’s simple, but not user-friendly for end users, and it doesn’t provide host- or path-based routing or TLS termination. For host/path routing and easier external access, use an Ingress with an ingress controller.

Use Ingress for host/path-based routing (NGINX ingress controller)

Ingress is a cluster resource that defines routing rules (host/path) and optionally TLS termination. An ingress controller (e.g., NGINX) watches Ingress objects and programs a reverse proxy accordingly. Check that an NGINX ingress controller is running in the ingress-nginx namespace and that its Service is present:
Because the ingress controller Service maps node port 30080 → 80, hitting node:30080 reaches the ingress controller.

Add a second backend (api) for path-based routing

Create a second backend deployment api using HashiCorp’s http-echo image so it returns a simple response, then expose it as api-svc:

Create an Ingress resource with path-based rules

Save the following as ingress.yaml (it rewrites paths to / and routes /api to api-svc:5678 and / to web-svc:80):
Apply the Ingress and inspect it:
Test the routing via the ingress controller NodePort (30080):
The same NodePort (30080) and cluster IP are now used by the ingress controller to route requests to different backends based on the paths defined in the Ingress resource.

Summary: the three routing layers

Ingress routes to Services, and Services route to Pods. Remember these three layers:

Debugging checklist (outside → inside)

  1. Can’t reach the app externally?
    • Verify the ingress controller pod(s) and Service are running.
    • Confirm the ingress controller Service exposes ports (NodePort or LoadBalancer).
  2. Ingress reachable but wrong backend?
    • Inspect the Ingress resource: kubectl describe ingress <name>.
    • Check annotations (e.g., rewrite rules) and ingressClassName.
  3. Service has no endpoints?
    • Check Service selectors and Pod labels: kubectl describe svc <svc> and kubectl get pods --show-labels.
    • Confirm pods are listening on the expected targetPort.
When troubleshooting, always follow the chain: Ingress → Service → Pod. Verify the ingress-controller is running, the Ingress rules point to the correct services, and the Services select the appropriate Pods (labels and ports).

Further reading and references

Watch Video