Services and Networking
Pods are ephemeral, when one is replaced (a rollout, a crash, a rescheduled Pod), it gets a brand new IP address. Nothing that depends on a Pod's IP directly would survive that. A Service gives a stable network identity in front of a changing set of Pods.
Why you can't just use Pod IPs
Pod IP: 10.244.1.7 → crashes, replaced → new Pod IP: 10.244.2.3
Anything that hardcoded 10.244.1.7 breaks the moment that Pod is replaced. A Service solves this with a stable virtual IP and DNS name that automatically routes to whichever Pods currently match its selector.
Defining a Service
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
selector: app: web means this Service load-balances traffic across every Pod carrying that label, exactly the same label used by the Deployment's template. Other Pods in the cluster can now reach this Service at the DNS name web (or web.<namespace>.svc.cluster.local in full).
Service types
| Type | What it does |
|---|---|
ClusterIP (default) | Only reachable from inside the cluster |
NodePort | Also exposes a fixed port on every node's IP |
LoadBalancer | Asks the cloud provider to provision an external load balancer |
Most internal, service-to-service traffic uses ClusterIP, you only reach for LoadBalancer for something the outside world needs to hit directly, like a public-facing web frontend.
Labels and selectors tie it all together
Labels are simple key-value pairs attached to any Kubernetes object, and selectors are how Deployments, Services, and other resources find the right Pods to act on:
labels:
app: web
environment: production
WARNING
A Service with a selector that doesn't match any Pod's labels silently "works" (it exists and has a DNS name), but routes traffic to nowhere, an extremely common, very confusing first Kubernetes bug. Always double check the label spelling matches exactly on both sides.