Skip to main content
Kubernetes intermediate Lesson 4 of 8

Services and Networking

Learn how Services expose Pods reliably using stable virtual IPs, DNS, and service types — with hands-on YAML examples.

Why Services Exist

Pods are ephemeral. When a Pod dies and a new one starts, it gets a different IP.

A Service solves this by:

  1. Using label selectors to track which Pods are healthy
  2. Maintaining a stable ClusterIP and DNS name regardless of Pod churn
  3. Load-balancing traffic across all matching Pods
Client → Service (stable IP: 10.96.0.1) → Pod A (10.244.0.3)
                                         → Pod B (10.244.0.4)
                                         → Pod C (10.244.0.5)

ClusterIP (Default)

Internal-only access. The most common type for pod-to-pod communication.

# service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:
  name: api-service
spec:
  selector:
    app: api          # routes to pods with this label
  ports:
    - protocol: TCP
      port: 80        # port on the Service
      targetPort: 8080  # port on the Pod
  type: ClusterIP
kubectl apply -f service-clusterip.yaml

# View the service and its ClusterIP
kubectl get service api-service
kubectl describe service api-service

# Test from inside a temporary pod
kubectl run test --rm -it --image=curlimages/curl -- sh
# Inside the pod:
curl http://api-service        # same namespace
curl http://api-service.default.svc.cluster.local  # fully qualified

NodePort

Exposes the service on every node’s IP at a static port. Mainly used for development or legacy load balancers.

# service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:
  name: api-nodeport
spec:
  selector:
    app: api
  ports:
    - protocol: TCP
      port: 80          # internal cluster port
      targetPort: 8080  # pod port
      nodePort: 30080   # port exposed on every node (30000–32767)
  type: NodePort
kubectl apply -f service-nodeport.yaml

# Access via any node IP
kubectl get nodes -o wide   # get node external IP
curl http://<node-ip>:30080

# With minikube
minikube service api-nodeport --url

LoadBalancer

Provisions a cloud load balancer (AWS ELB, GCP LB, Azure LB). Gives you a public IP.

# service-lb.yaml
apiVersion: v1
kind: Service
metadata:
  name: api-lb
spec:
  selector:
    app: api
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: LoadBalancer
kubectl apply -f service-lb.yaml

# Watch for EXTERNAL-IP to be assigned (takes a minute on cloud)
kubectl get service api-lb --watch

With minikube, run minikube tunnel in a separate terminal to simulate a LoadBalancer IP.

Service Types Summary

TypeAccess scopeUse case
ClusterIPInside cluster onlyPod-to-pod communication
NodePortNode IP + static portDev/testing, legacy setups
LoadBalancerExternal IP from cloudProduction internet-facing apps
ExternalNameDNS alias to external serviceAbstracting external APIs

DNS-Based Service Discovery

# Every service is reachable via DNS inside the cluster:
# <service-name>.<namespace>.svc.cluster.local

# Same namespace: just use service name
curl http://api-service

# Cross-namespace: include namespace
curl http://api-service.production.svc.cluster.local

# Check DNS from inside a pod
kubectl run dns-test --rm -it --image=busybox -- nslookup api-service

Endpoints

Kubernetes automatically tracks healthy Pod IPs in an Endpoints object.

# See which Pod IPs the service is forwarding to
kubectl get endpoints api-service

# If endpoints are empty, check your selector labels match pod labels
kubectl get pods --show-labels
kubectl describe service api-service | grep Selector

Headless Service (StatefulSets)

A headless service returns individual Pod DNS names instead of a ClusterIP — used with StatefulSets so each pod is addressable.

apiVersion: v1
kind: Service
metadata:
  name: db-headless
spec:
  clusterIP: None       # headless — no virtual IP
  selector:
    app: db
  ports:
    - port: 5432
# DNS returns individual pod addresses, e.g.:
# db-0.db-headless.default.svc.cluster.local
# db-1.db-headless.default.svc.cluster.local

Learning Outcomes

You can:

  • Write ClusterIP, NodePort, and LoadBalancer Service manifests
  • Explain label selection and how endpoints are maintained
  • Use DNS for service discovery inside a cluster
  • Debug services with kubectl describe, kubectl get endpoints

Frequently Asked Questions

Why not connect directly to Pod IPs?
Pod IPs are ephemeral—Pods can be recreated with new IPs at any time. Services provide a stable endpoint backed by automatic endpoint tracking.
How does DNS work inside the cluster?
Kubernetes runs CoreDNS. Every Service gets a DNS name in the form <service>.<namespace>.svc.cluster.local. Pods in the same namespace can reach it by just the service name.