Services, Deployments and policies find their pods only through label selectors.
Labels are short key-value pairs in metadata.labels, such as app: web, tier: frontend, env: prod. They don't do anything by themselves; they let other objects and people select groups.
A selector matches labels:
- equality:
app=web,env!=prod - set-based:
env in (staging,prod),tier notin (cache),!canary
On the command line: kubectl get pods -l app=web,env=prod. In objects: a Service's spec.selector picks the pods that receive its traffic, and a Deployment's spec.selector.matchLabels (or matchExpressions) picks the pods it owns.
This loose coupling is powerful: relabel a pod and it leaves a Service's endpoints, which is handy for pulling a misbehaving pod out of rotation for debugging. It's also a trap: two Deployments with overlapping selectors fight over the same pods.
The recommended common labels are app.kubernetes.io/name, app.kubernetes.io/instance, app.kubernetes.io/version, app.kubernetes.io/component and app.kubernetes.io/part-of; tools like Helm set them.
Annotations are for data that is not used to select things: build info, a change cause, tool configuration (ingress controllers and Prometheus read annotations). They can be large; labels are limited to 63-character values.
Example
kubectl get pods --show-labels
# NAME READY STATUS LABELS
# web-7f9-a 1/1 Running app=web,pod-template-hash=7f9...
# api-5c4-b 1/1 Running app=api,tier=backend
kubectl get pods -l 'app in (web,api)'
kubectl get pods -l tier!=backend
# take a pod out of its Service's endpoints for debugging
kubectl label pod web-7f9-a app=web-debug --overwrite
# the ReplicaSet no longer matches it and creates a replacement
kubectl annotate deploy web team=paymentsRemember
- Selectors connect Services and controllers to pods
- Equality and set-based selectors; -l on the CLI
- Annotations hold non-selecting metadata, often read by tools
Watch out for
- Overlapping selectors between two Deployments, which then fight over each other's pods.