09 · Services
Pods are ephemeral. They get new IP addresses when they restart, and they come and go as deployments scale and roll out. Services provide a stable network endpoint that other workloads can rely on, regardless of which Pods are actually running.
The Problem
A Deployment creates Pods with random names and IPs: 10.0.0.5, 10.0.0.12, 10.0.0.23. When Pod 10.0.0.5 crashes and is replaced, the new Pod gets a different IP. Any other service that hardcoded 10.0.0.5 is now broken.
Services solve this by providing a stable virtual IP (ClusterIP) and DNS name that maps to the current set of healthy Pods.
How Services Work
A Service selects Pods using label selectors and maintains an Endpoints object listing the IPs of matching Pods.
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web # selects all pods with label app=web
ports:
- port: 80 # port the Service listens on
targetPort: 8080 # port on the Pod
When a client connects to the Service's ClusterIP on port 80, kube-proxy (running on each node) forwards the traffic to one of the matching Pods on port 8080. The selection is random by default (roughly round-robin via iptables or IPVS).
Service Types
ClusterIP (default)
A virtual IP accessible only within the cluster. Use this for internal service-to-service communication.
The DNS name is automatically available to all Pods in the cluster.
NodePort
Exposes the Service on a static port on every node's IP (default range: 30000–32767).
Useful for development and simple setups. Not recommended for production: it exposes a port on every node, and load balancing is only as good as how traffic reaches the nodes.
LoadBalancer
Provisions an external cloud load balancer (AWS ALB/NLB, GCP Load Balancer, Azure Load Balancer). The LB forwards traffic to the NodePort on healthy nodes.
Simple to set up but expensive: one load balancer per Service. For many HTTP services, use Ingress instead (one load balancer routes to many services).
ExternalName
Maps a Service to an external DNS name. Useful for integrating external databases or services using Kubernetes DNS.
Headless Services
Setting clusterIP: None creates a headless Service. Instead of a virtual IP, DNS resolves directly to the IPs of the Pods.
DNS query for mysql.default.svc.cluster.local returns all Pod IPs. Used by StatefulSets to give each Pod a stable DNS address (mysql-0.mysql, mysql-1.mysql).
Service DNS
Every Service gets a DNS name in the cluster:
Pods in the same namespace can use the short form:
# From a pod in the "default" namespace:
curl http://web # works (same namespace)
curl http://web.default # works
curl http://web.default.svc.cluster.local # works (fully qualified)
# Accessing a service in another namespace:
curl http://api.backend # from default, accessing "api" in "backend" namespace
Summary
| Type | Accessible from | Use case |
|---|---|---|
| ClusterIP | Inside cluster | Service-to-service communication |
| NodePort | Outside cluster (via node IP) | Dev/test, simple external access |
| LoadBalancer | Outside cluster (via cloud LB) | Production external access |
| ExternalName | Inside cluster | Alias to external DNS |
| Headless | Inside cluster (direct Pod DNS) | StatefulSets, client-side LB |
For exposing many HTTP services to the internet, combine a single LoadBalancer or NodePort with an Ingress controller — the subject of the next post.