Labels and annotations
Almost nothing in Kubernetes refers to anything else by name. Objects find each other through labels and selectors, and a great many “why is nothing connecting?” problems are a selector matching nothing.
Reference
- https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
- https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
Terminology
- Label — A key/value pair attached to an object, intended to be selected on. Labels are indexed, so querying by them is cheap. Keys and values are constrained: 63 characters, alphanumeric with
-,_,.. - Annotation — A key/value pair that is not selected on. Annotations are for tools and humans: build IDs, git commits, dashboard URLs, ingress configuration. Values can be large and unstructured.
- Selector — A query over labels.
matchLabelsis equality-based;matchExpressionsaddsIn,NotIn,ExistsandDoesNotExist. - Set-based selector — A selector using
matchExpressions, which can express things equality cannot: “has this label at all”, or “one of these three environments”. - Owner reference — How one object owns another. A Deployment owns ReplicaSets, which own Pods. Deletion cascades along this chain, and it is separate from labels — a common source of confusion.
The rule of thumb: if you would ever want to select on it, it is a label. If not, it is an annotation. Labels are for the cluster; annotations are for everything else.
Who Selects What
Deployment ──selects──▶ ReplicaSet ──selects──▶ Pods
▲
Service ────────────────selects───────────────────┘
NetworkPolicy ──────────selects───────────────────┘
PodDisruptionBudget ────selects───────────────────┘Every arrow is a label selector. Change a Pod’s labels so they no longer match its Deployment’s selector, and the Deployment will create a replacement while the orphan keeps running — two Pods where you expected one. Change a Service’s selector and its Endpoints empty out.
Selecting From The Command Line
kubectl get pods --show-labels
kubectl get pods -l app=web
kubectl get pods -l 'app in (web,api)'
kubectl get pods -l 'tier!=frontend' # includes pods with no tier label at all
kubectl get pods -l app=web,tier=frontend # ANDThat third example is the one that surprises people: != matches objects that do not have the label, as well as those with a different value.
Exercises
Add and change labels.
kubectl run probe --image=docker.io/library/nginx:1.27 --labels=app=probe kubectl get pod probe --show-labels kubectl label pod probe tier=frontend kubectl get pods -l tier=frontendWatch a Service lose its endpoints. Create a Deployment and a Service that selects it, confirm the Endpoints are populated, then relabel the Pods so the selector no longer matches:
kubectl create deployment web --image=docker.io/library/nginx:1.27 --replicas=2 kubectl expose deployment web --port=80 kubectl get endpoints web # two addresses kubectl label pod -l app=web app=renamed --overwrite kubectl get endpoints web # emptyThe Service is healthy, the Pods are healthy, and traffic goes nowhere. This is the single most useful diagnostic skill in this module.
Use a set-based selector. Create a PodDisruptionBudget or NetworkPolicy with
matchExpressionsand confirm withkubectl get <kind> -o yamlthat it was stored as you meant.Annotate something. Annotations do nothing on their own, which is the point:
kubectl annotate pod probe owner=you reason=testing kubectl get pod probe -o jsonpath='{.metadata.annotations}{"\n"}'
What to Take Away
- Objects refer to each other by selector, not by name.
- Labels are for selecting; annotations are for everything else.
kubectl get endpoints <service>is the fastest way to find out whether a selector is doing what you think.- If you see more Pods than you asked for, look for one whose labels stopped matching its owner.
Where This Is Practised
Lab 01 in the workbook is built around this. Run labctl list to see whether it is ready yet.