Services Deep Dive¶
What You'll Learn¶
- What each of the four Service types actually does, and when to use each
- How kube-proxy turns a Service into real traffic routing — iptables mode vs. IPVS mode
- How Endpoints/EndpointSlices track which pods are live, and how session affinity works
Why This Matters¶
A Service looks like a single YAML object with a type field, but that field selects between four genuinely different mechanisms — one is purely internal DNS/VIP routing, one opens a port on every node, one provisions cloud infrastructure, and one isn't really a proxy at all. Picking the wrong one is a common source of "why can't I reach this from outside the cluster" and "why is this exposed to the internet when it shouldn't be."
Mental Model¶
A Service is a stable virtual IP and DNS name in front of a changing set of pods. It exists because pod IPs are ephemeral — a Service gives callers something that doesn't change even as the pods behind it are created, killed, and replaced.
| Type | Reachable from | Mechanism |
|---|---|---|
ClusterIP (default) |
Inside the cluster only | Stable virtual IP, routed by kube-proxy |
NodePort |
Outside, via <any-node-ip>:<30000-32767> |
Builds on ClusterIP, plus a port opened on every node |
LoadBalancer |
Outside, via a cloud load balancer's IP/DNS | Builds on NodePort, plus a cloud LB provisioned by the cloud controller manager |
ExternalName |
Internally, via DNS CNAME only | No proxying at all — just a DNS alias to an external name |
How It Works¶
ClusterIP and headless Services¶
apiVersion: v1
kind: Service
metadata:
name: checkout-api
spec:
type: ClusterIP
selector:
app: checkout-api
ports:
- port: 80
targetPort: 8080
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 3600
Setting clusterIP: None makes it headless — no virtual IP, no load-balancing. DNS queries for the Service name return the individual pod IPs directly (or, for a StatefulSet, stable per-pod DNS names). Use a headless Service when the client needs to pick or address a specific backend pod, not "any healthy one."
NodePort and LoadBalancer¶
apiVersion: v1
kind: Service
metadata:
name: checkout-api-public
spec:
type: LoadBalancer
selector:
app: checkout-api
ports:
- port: 443
targetPort: 8443
nodePort: 31443 # optional explicit port, otherwise auto-assigned 30000-32767
LoadBalancer is a superset of NodePort: the cloud controller manager provisions an external load balancer (ELB/ALB, Cloud Load Balancer, etc.) and points it at the NodePort on every node. In a bare-metal cluster with no cloud integration, type: LoadBalancer gets stuck <pending> forever unless something like MetalLB is installed to fulfill it.
ExternalName¶
apiVersion: v1
kind: Service
metadata:
name: legacy-db
spec:
type: ExternalName
externalName: db.legacy.internal.example.com
No selector, no ports, no proxying — this just makes legacy-db.default.svc.cluster.local resolve as a CNAME to the external hostname, so in-cluster code can use a consistent internal name for something that lives outside the cluster.
How kube-proxy actually implements a Service¶
flowchart LR
A[Pod dials ClusterIP:80] --> B{kube-proxy mode}
B -->|iptables| C[DNAT rule rewrites dest to a randomly chosen pod IP]
B -->|IPVS| D[IPVS virtual server load-balances across registered real servers]
C --> E[Pod IP:targetPort]
D --> E
| Mode | How it works | Trade-offs |
|---|---|---|
iptables (long-time default) |
Chains of DNAT rules per Service/endpoint, evaluated roughly linearly | Simple, but rule count grows with Service count — slower updates at very large scale |
IPVS |
Kernel-level load balancer (Linux IPVS), Services registered as virtual servers | O(1) lookup regardless of Service count, more LB algorithm choices (round robin, least connection, etc.) — the better choice for large clusters |
Some CNI plugins (notably Cilium) replace kube-proxy's job entirely with an eBPF datapath, skipping iptables/IPVS altogether for lower latency and better observability.
Endpoints and EndpointSlices¶
kubectl get endpoints checkout-api
kubectl get endpointslices -l kubernetes.io/service-name=checkout-api
The classic Endpoints object lists every ready pod IP for a Service in one flat object — this doesn't scale well past a few thousand pods behind one Service. EndpointSlices (the modern default) shard that list into multiple smaller objects, which is both more efficient to update and lets kube-proxy/CNI process incremental changes instead of rewriting one giant object every time a pod's readiness flips.
Session affinity¶
sessionAffinity: ClientIP makes kube-proxy route repeated requests from the same client IP to the same backend pod, for up to timeoutSeconds. It's the closest thing a plain Service has to sticky sessions — there's no cookie-based affinity at the Service layer; that requires an Ingress controller or a service mesh.
Common Mistakes¶
- Using
type: LoadBalancerfor every internal Service — each one provisions real, billed cloud infrastructure; internal-only traffic should stayClusterIPand go through an Ingress if it needs a single external entry point. - Expecting a headless Service to load-balance — by definition it doesn't; clients get all pod IPs and must choose (or rely on the client library to).
- Forgetting that Service selectors match on pod labels, not names — a typo'd label silently produces a Service with zero endpoints (
kubectl get endpointsshows<none>). - Assuming
sessionAffinity: ClientIPbehaves like cookie-based sticky sessions — it keys purely on source IP, which breaks down behind NAT or shared corporate egress IPs. - Not checking kube-proxy mode when debugging performance at scale — a cluster still on
iptablesmode with thousands of Services can see real latency in rule evaluation and updates.
Interview Questions¶
- Explain the difference between all four Service types and give a real use case for each.
- How does kube-proxy actually get traffic from a ClusterIP to a specific pod, in either mode?
- Why do EndpointSlices exist when Endpoints already did the job?
- What's the practical difference between a headless Service and a normal ClusterIP Service?
See Interview Prep for full answers.
Next¶
Continue to Ingress and Ingress Controllers for routing HTTP/HTTPS traffic into multiple Services through one entry point.