What is a Kubernetes Service, and why is it needed given Pods are ephemeral?
Quick Answer
A Service provides a single, stable virtual IP address and DNS name that load-balances traffic across a dynamic, changing set of Pods matched by a label selector — since Pods are created and destroyed constantly (rescheduled, scaled, replaced during rollouts) and each gets a new IP address every time, nothing else in the cluster could reliably address them directly. A Service decouples "who I need to talk to" from "which specific Pod IPs currently exist," with Kubernetes keeping the mapping continuously up to date.
Detailed Answer
The problem: Pod IPs are not stable
Every Pod gets its own IP address when it starts — but that address is not durable. If a Pod crashes and is replaced, is rescheduled to a different node, or is part of a rolling update replacing it with a new version, the replacement gets a different IP address. Hardcoding a Pod's IP anywhere (in another application's configuration, in a load balancer) would break constantly as normal cluster operation replaced Pods.
Deployment "web" with 3 replicas might have Pod IPs:
10.1.2.3, 10.1.2.4, 10.1.2.5 -- right now
After a rolling update or a node failure and rescheduling:
10.1.3.7, 10.1.2.4, 10.1.4.1 -- completely different set, moments later
What a Service provides
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web # matches Pods with this label
ports:
- port: 80 # the Service's own stable port
targetPort: 8080 # the port the Pods actually listen on
A Service gets its own stable virtual IP (a ClusterIP) and DNS name (web.default.svc.cluster.local) that never changes for the Service's lifetime, regardless of how many times its backing Pods are replaced. Any other Pod in the cluster can reliably reach http://web (or http://web.default.svc.cluster.local from another namespace) and have traffic routed to one of the currently-healthy Pods matching the app: web label selector — without ever needing to know or track individual Pod IPs.
How the mapping stays current
The Service continuously watches for Pods matching its selector, and an associated Endpoints (or EndpointSlice — see that question) object is kept up to date with the current set of healthy backing Pod IPs. kube-proxy on every node uses this list to program local networking rules (iptables/IPVS/eBPF, depending on configuration) that route traffic sent to the Service's virtual IP to one of the currently-listed healthy Pod IPs.
Why this is the foundational abstraction for nearly everything else
Deployments, StatefulSets, Ingress, and service meshes all build on top of the basic guarantee a Service provides: a stable way to address a set of Pods without caring about individual Pod identity or IP churn. Understanding "Services solve the problem of ephemeral Pod IPs by providing a stable, load-balanced front" is the conceptual anchor for the entire networking topic — every other networking object (Ingress routing to Services, NetworkPolicies restricting traffic to/from Pods a Service fronts, headless Services for StatefulSets) is a variation or extension of this same core need.