Lesson 8 / 25
Services and Label Selectors
A stable address in front of changing pods.
Selector -> endpoints
A Service gives a set of pods a stable virtual IP and DNS name, and load-balances across them. It finds its pods with a label selector; Kubernetes keeps the list of matching, ready pods (endpoints) up to date. Types: ClusterIP (internal only, the default), NodePort (a port on every node), LoadBalancer (a cloud load balancer). port is what clients use; targetPort is the container port. A selector that is too broad routes traffic to pods you did not intend.
Stable names for moving pods
Services select pods by label; Ingress and Gateway route outside traffic; DNS ties it together.
Generating a ClusterIP Service, run
I ran this with kubectl 1.37.0 using --dry-run=client (or kubectl kustomize), which generates manifests locally without a cluster; nothing was applied to a live cluster. Clients connect to port 80; traffic goes to port 8080 on pods labelled app=web.
kubectl create service clusterip web --tcp=80:8080 --dry-run=client -o yaml
Output:
apiVersion: v1
kind: Service
metadata:
labels:
app: web
name: web
spec:
ports:
- name: 80-8080
port: 80
protocol: TCP
targetPort: 8080
selector:
app: web
type: ClusterIP
status:
loadBalancer: {}Which pods does a selector match? run
I ran this with Python 3. It is a simplified model of Kubernetes behaviour for learning, not the real controller code. Selector app=web also matches a stray debug pod; adding tier=frontend excludes it; adding version=1.5 selects only the new version, which is how some canary setups route traffic.
pods = [
{"name": "web-7c9-a", "labels": {"app": "web", "tier": "frontend", "version": "1.4"}},
{"name": "web-7c9-b", "labels": {"app": "web", "tier": "frontend", "version": "1.5"}},
{"name": "api-55f-a", "labels": {"app": "api", "tier": "backend"}},
{"name": "debug-pod", "labels": {"app": "web"}},
]
def matches(selector, labels): # equality-based selector: every key must match
return all(labels.get(k) == v for k, v in selector.items())
for sel in [{"app": "web"}, {"app": "web", "tier": "frontend"}, {"app": "web", "version": "1.5"}]:
print(sel, "->", [p["name"] for p in pods if matches(sel, p["labels"])])
Output:
{'app': 'web'} -> ['web-7c9-a', 'web-7c9-b', 'debug-pod']
{'app': 'web', 'tier': 'frontend'} -> ['web-7c9-a', 'web-7c9-b']
{'app': 'web', 'version': '1.5'} -> ['web-7c9-b']Quick check: How does a Service know which pods to send traffic to?
- By pod name prefix
- By pod IP addresses written in the Service
- Its label selector matches pod labels, and only ready pods receive traffic
- Randomly across the cluster
Answer
Its label selector matches pod labels, and only ready pods receive traffic — Labels connect Services to pods.