Kubernetes Tutorial — Part 4: Services, Networking, and Load Balancing

By Suraj Ahir March 13, 2026 11 min read

← Part 3 Kubernetes Tutorial · Part 4 of 12 Part 5 →
Kubernetes Services and Networking
Kubernetes Services route traffic to the right pods automatically

Here is a problem with everything we built in Part 3. Yes, our Deployment keeps three nginx pods running and self-heals when they crash. But every time a pod is recreated, it gets a brand new IP address. If you have a frontend application trying to send requests to the backend, the IP it knew about is now stale. The pod is gone, replaced by a new one with a different address.

This is not a theoretical problem. It is the fundamental networking challenge of containerised environments. Before Kubernetes, people solved this by registering services in external tools like Consul or Zookeeper. Kubernetes solves it natively through Services.

A Kubernetes Service is a stable virtual IP and DNS name that sits in front of a set of pods. It never changes, even as pods come and go. All traffic going to the Service gets automatically load-balanced across the healthy pods behind it. This is how every part of your application finds and talks to every other part.

How Pod Networking Actually Works

Every pod in Kubernetes gets its own IP address. Pods on the same node can communicate directly. Pods on different nodes use an overlay network — Kubernetes automatically handles routing between nodes. From a pod's perspective, every other pod in the cluster is reachable by IP, no matter which node it is on.

But pod IPs are not stable — they are assigned from a pool and change when pods restart. Services solve this by providing a stable virtual IP (called a ClusterIP) that stays constant, with Kubernetes automatically updating the routing behind the scenes whenever the pods change.

The Three Types of Kubernetes Services

Kubernetes has three main Service types, each suited to different use cases. Understanding which to use is essential for designing production applications.

ClusterIP — The default type. Creates a virtual IP that is only accessible from within the cluster. Used for internal communication between services — for example, your frontend pods talking to your backend pods, or your backend talking to Redis. External users cannot reach a ClusterIP Service directly.

NodePort — Opens a specific port on every node in the cluster and routes traffic from that port to the Service. This makes your application accessible from outside the cluster using any node's IP and the assigned port. Ports are in the range 30000–32767. NodePort is good for development and testing but not ideal for production because it exposes ports directly on your nodes.

LoadBalancer — When running in a cloud environment (AWS, GCP, Azure), this type automatically provisions a cloud load balancer with a public IP and routes traffic to your pods. This is the standard way to expose production applications in the cloud. On Minikube, you need to run minikube tunnel for LoadBalancer to work.

Creating a ClusterIP Service

Let us create a Deployment with a ClusterIP Service to understand internal pod communication.

backend-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
    spec:
      containers:
      - name: backend
        image: nginx:1.25
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: backend-service
spec:
  type: ClusterIP
  selector:
    app: backend
  ports:
  - port: 80
    targetPort: 80
Apply and inspect the Service
kubectl apply -f backend-deployment.yaml

kubectl get services
kubectl describe service backend-service

# Get the ClusterIP assigned
kubectl get service backend-service -o jsonpath='{.spec.clusterIP}'

The selector: app: backend in the Service definition is critical. This is how the Service knows which pods to route traffic to — it looks for pods with the matching label. When you add or remove pods from the Deployment, the Service automatically includes or excludes them based on this label selector.

Creating a NodePort Service

NodePort lets you access your application from outside the cluster. This is what we use during local development with Minikube.

frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: frontend-service
spec:
  type: NodePort
  selector:
    app: frontend
  ports:
  - port: 80
    targetPort: 80
    nodePort: 30080  # Optional: specify the port, or let Kubernetes assign one
Access NodePort service via Minikube
kubectl apply -f frontend-service.yaml

# Get the URL to access the service in Minikube
minikube service frontend-service --url

# Or open it directly in browser
minikube service frontend-service

Service Discovery with DNS

This is one of my favourite features in Kubernetes. When you create a Service, Kubernetes automatically registers it in the cluster DNS. Any pod in the cluster can reach that service by its name — no IP addresses needed, no configuration files, nothing.

If you have a service named backend-service in the default namespace, any pod in the same namespace can reach it at simply backend-service. The full DNS name is backend-service.default.svc.cluster.local, but within the same namespace you can just use the short name.

Test DNS-based service discovery
# Run a temporary pod to test connectivity
kubectl run test-dns --image=busybox --rm -it -- /bin/sh

# Inside the pod, try to reach the backend service by name
wget -qO- http://backend-service

# Try the full DNS name
wget -qO- http://backend-service.default.svc.cluster.local

# Exit the pod (it deletes itself because of --rm)
exit

The fact that services find each other by name rather than IP is what makes microservices architecture in Kubernetes so clean. Your frontend code just calls http://backend-service/api and Kubernetes handles all the routing. This is the same in development and production — no environment variables needed for internal service URLs.

Endpoints — What Powers Services Under the Hood

When a Service routes traffic to pods, it uses an Endpoints object. Kubernetes automatically creates and maintains an Endpoints object for each Service, listing the IP addresses and ports of all healthy pods that match the Service's selector.

Inspect service endpoints
# See the endpoints (pod IPs) behind a service
kubectl get endpoints backend-service

# Watch endpoints change as pods come and go
kubectl get endpoints backend-service -w

Run this and then delete one of your backend pods in another terminal. You will see the endpoint list update immediately, removing the deleted pod's IP. This is how the Service always routes to healthy pods only.

LoadBalancer Type with Minikube Tunnel

Create a LoadBalancer service and test it
# Create LoadBalancer service
kubectl expose deployment backend --type=LoadBalancer --port=80

# In Minikube, run tunnel to assign an external IP (run in separate terminal)
minikube tunnel

# Check the external IP assignment
kubectl get service backend
# EXTERNAL-IP should now show an IP instead of 

Useful Service Commands

Common Service operations
# List all services
kubectl get services

# Describe a service in detail
kubectl describe service backend-service

# Delete a service
kubectl delete service backend-service

# Expose an existing deployment as a service (shortcut)
kubectl expose deployment my-app --type=NodePort --port=80

# Edit a service in place
kubectl edit service backend-service

# Get service as YAML
kubectl get service backend-service -o yaml

What is Next

You now understand the networking layer of Kubernetes. You know how pods communicate internally using ClusterIP Services and DNS, how to expose applications externally with NodePort and LoadBalancer, and how Kubernetes keeps service endpoints up to date as pods change.

But there is still something missing. Your pods are currently getting their configuration — database URLs, API keys, feature flags — baked into the container image or hardcoded. That is terrible practice. In Part 5, we cover ConfigMaps and Secrets — the proper way to manage application configuration and sensitive data in Kubernetes.

Frequently Asked Questions

Why do Kubernetes pods need Services?

Pod IP addresses change every time a pod restarts. Services provide a stable virtual IP and DNS name that never changes, giving other pods a reliable address to communicate with regardless of how often the underlying pods are replaced.

What is the difference between ClusterIP, NodePort, and LoadBalancer?

ClusterIP is internal-only (pod-to-pod). NodePort opens a port on every cluster node for external access. LoadBalancer provisions a cloud load balancer with a public IP — the standard for production external traffic in cloud environments.

How does Kubernetes load balance traffic between pods?

kube-proxy on each node uses iptables or IPVS rules to route Service traffic to pods using round-robin by default. Unhealthy pods are automatically removed from rotation, so only working pods receive traffic.

How does DNS work in Kubernetes?

CoreDNS automatically creates a DNS record for every Service. Pods in the same namespace can reach a service by its short name. Cross-namespace requires the full name: service-name.namespace.svc.cluster.local. No manual configuration needed.

How do I expose my application to the internet?

Use NodePort for simple external access (good for dev), LoadBalancer in cloud environments for production, or Ingress (covered in Part 8) which is the recommended production approach for routing multiple services through one load balancer.

Key takeaways

Continue reading
Part 5 — Services and Networking
How pods actually talk.
Suraj Ahir — author of SRJahir Tech

Written by

Suraj Ahir

Cloud & DevOps engineer running four live production services on my own AWS infrastructure. I write everything on this site myself — no ghostwriters, no AI filler.

← Part 3 Kubernetes Tutorial · Part 4 of 12 Part 5 →
← Back to Blog
Disclaimer: This content is for educational purposes only. SRJahir Tech does not guarantee any specific outcome, job placement, or exam result. Learning requires consistent effort and practical application.