skip to content

API Object Conventions

Every Kubernetes resource shares one shape: labels that let objects find each other, ObjectMeta the server writes, apply rules that merge your YAML into the cluster, and ownerReferences deciding what dies with what. The rest of the API assumes this vocabulary.

part ofKubernetesoverview, primer and where to startread it →
on this pageshow

questions

13

In Kubernetes, what is the difference between a label and an annotation, and how do you decide which one to use?

level: juniorimportance: must knowfreq 78%

answer

  1. identify versus describe
  2. which one can a selector match
  3. 63-character value limit on one side
  4. 256 KiB total on the other
  5. kubectl apply stores its manifest there

basics

~20 s

Labels are short identifying key/value pairs that selectors match, so Services, Deployments and kubectl -l find objects by them. Annotations carry non-identifying data of any shape, capped at 256 KiB in total, that tools read by key but nothing can select on.

solid answer

~50 s

Both are string maps in `metadata` and share the same key syntax: an optional DNS-subdomain prefix plus a name of up to 63 characters. **Labels identify**: values are capped at 63 characters from a restricted character set, and they are what selection works on — a Service's selector, a Deployment's `.spec.selector` and `kubectl get -l` all match labels. **Annotations describe**: a value can be any string, including multi-line JSON, limited only by 262144 bytes for all keys and values together, and no selector can query them. Tools and controllers read them by key — `kubectl apply` stores `kubectl.kubernetes.io/last-applied-configuration`, and the Deployment controller writes `deployment.kubernetes.io/revision`. The fast check: if anything will ever need to *find or group* objects by the value, it is a label; if it is information *about* the object, such as a build commit, an on-call contact or a tool setting, it is an annotation.

code

yaml · 27 lines
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: game-session
  labels:
    app.kubernetes.io/name: game-session
    games.example.com/store-tier: flagship
  annotations:
    games.example.com/build-commit: "9f2c41e"
    games.example.com/oncall: "store-edge-team"
    games.example.com/build-log: "https://ci.example.com/builds/5827"
spec:
  replicas: 2
  selector:
    matchLabels:
      app.kubernetes.io/name: game-session
  template:
    metadata:
      labels:
        app.kubernetes.io/name: game-session
    spec:
      containers:
      - name: server
        image: registry.example.com/game-session:2.14.3
        resources:
          requests:
            cpu: 350m

go deeper

for a junior

Recall the split: labels identify and can be selected, annotations describe and cannot. Name one example of each, such as app.kubernetes.io/name and a build commit.

for a middle

Explain the constraints behind the split: 63-character constrained label values versus unrestricted annotation values under a 262144-byte total, and name built-in annotations like last-applied-configuration and deployment.kubernetes.io/revision.

for a senior

Show you have seen annotations fail in production: the size limit hit through client-side apply, and typo'd controller annotations silently ignored because nothing validates them.

for a principal

Frame labels as a shared, governed vocabulary the whole platform selects on, and annotations as per-tool configuration channels that need naming prefixes and ownership conventions to stay manageable.

## Two maps in every object's metadata Every persisted Kubernetes object has a `metadata` block (the **ObjectMeta** type). Two of its fields are free-form string-to-string maps that you, rather than the API server, fill in: - `metadata.labels` — **identifying** attributes. - `metadata.annotations` — **non-identifying** attributes. They look almost identical in YAML, which is why interviewers ask how they differ. The difference is not the syntax; it is what the API server lets you do with them. ## Labels: small, identifying, selectable A **label** says what an object *is* in terms other objects can query. The API server supports **label selectors** on list and watch requests, so labels are the glue that lets objects find each other: - a Service picks its backend Pods by labels; - a Deployment's `.spec.selector` decides which Pods and ReplicaSets it owns; - `kubectl get pods -l app.kubernetes.io/name=game-session` filters by them. Because they are matched constantly, labels are deliberately **small and constrained**. A value is at most 63 characters, may be empty, and must start and end with an alphanumeric character with only `-`, `_` and `.` in between. Spaces, slashes and JSON are rejected. ## Annotations: arbitrary, non-identifying, never selected An **annotation** records information *about* an object that no selector will ever match on. The key follows the same rules as a label key, but the **value is unrestricted**: free text, a URL, a multi-line JSON document. The only size rule is a **total limit of 262144 bytes (256 KiB)** across all annotation keys and values on one object; a write over that is rejected with `metadata.annotations: Too long: must have at most 262144 bytes`. No selection is possible on annotations: there is no annotation-selector parameter on list requests, and no Service or workload can target Pods by one. Annotations are read **by key** — a component fetches the object and looks up the entry it cares about. ## Side by side | Aspect | Labels | Annotations | |---|---|---| | Purpose | Identify and group objects | Attach descriptive or tool data | | Value size | At most 63 characters | Any length, 262144-byte total per object | | Value characters | Alphanumerics plus `-`, `_`, `.` | Any string, including JSON | | Selectable | Yes — Services, workload selectors, `kubectl get -l` | No | | Typical readers | Controllers, the scheduler (via selectors), humans filtering | kubectl, controllers, CD tools, humans reading | | Key syntax | Optional DNS-subdomain prefix + `/` + name of at most 63 chars | Same as labels | Prefixes `kubernetes.io/` and `k8s.io/` are reserved for Kubernetes' own components; your keys should use a domain your team owns, such as `games.example.com/build-commit`. ## Annotations Kubernetes writes itself Seeing the built-in ones makes the purpose concrete: 1. `kubectl.kubernetes.io/last-applied-configuration` — client-side `kubectl apply` stores the full manifest you last applied here, as JSON. It is far too large and too unstructured to be a label. 2. `deployment.kubernetes.io/revision` — the Deployment controller numbers each rollout on the ReplicaSet and mirrors the current number onto the Deployment. 3. `kubectl.kubernetes.io/restartedAt` — `kubectl rollout restart` stamps a timestamp into the pod template. 4. `kubernetes.io/change-cause` — a human-written note that `kubectl rollout history` prints per revision. Ingress controllers, CD tools and operators use the same channel for their own settings. Because annotations are **not validated against any schema**, a mistyped key is simply ignored by whatever was meant to read it. ## Choosing in practice Take a **multiplayer game-session backend** running on a **5-node edge cluster in a retail store**, each pod requesting **0.35 core** (`cpu: 350m`). The team wants to record several facts on its Deployment: - the component name, `app.kubernetes.io/name: game-session` — a **label**, because the Service and the Deployment selector must find these pods; - the store tier, `games.example.com/store-tier: flagship` — a **label**, because dashboards and `kubectl get -l` will group by it; - the Git commit `9f2c41e` and a link to the build log — **annotations**, because nobody selects by a commit hash and a URL is not a legal label value; - the on-call contact and a 300-character JSON feature-flag summary — **annotations**, far past the 63-character label limit. A useful rule: labels answer *which ones?*, annotations answer *what about this one?*. Putting descriptive data into labels bloats every selector-indexed object and breaks on the character rules; putting identity into annotations means nothing can ever select on it.

  • What happens when an object's annotations grow past the size limit, and where does that usually bite?
    The API server rejects the write with `metadata.annotations: Too long: must have at most 262144 bytes`. The common trigger is client-side `kubectl apply` on a large ConfigMap: apply copies the whole manifest into `kubectl.kubernetes.io/last-applied-configuration`, so a ConfigMap with a few hundred KiB of data fails even though the ConfigMap itself is within its own limit. Creating or replacing it instead, or switching to server-side apply, avoids storing that copy.
  • Why does `kubectl annotate` refuse to change an annotation that already exists?
    `kubectl annotate` protects existing keys: setting a key that is already present fails unless you pass `--overwrite`, so a script cannot silently clobber a value another tool wrote. Appending a dash to the key, as in `games.example.com/build-commit-`, removes the annotation.
  • Who may use the `kubernetes.io/` and `k8s.io/` key prefixes?
    Those prefixes are reserved for Kubernetes core components and documented well-known keys. Your own labels and annotations should carry a prefix from a DNS domain your team controls, such as `games.example.com/`, so they cannot collide with keys the project or other tools define.

Labels are the colour-coded tags on warehouse shelves that pickers scan to find items; annotations are the packing slip taped inside the box, read only by whoever opens that particular box.

saying these in an interview costs you the question

  • A Service selector can match annotations just like labels.
  • Labels are the right place for long descriptions or JSON blobs.
  • Annotations are only comments that no Kubernetes component ever reads.
  • Label values can be any length as long as the object fits in etcd.
  • Every single annotation value has its own 63-character limit.
open as a page

In Kubernetes, how do `kubectl create -f`, `kubectl replace -f` and `kubectl apply -f` differ when you manage an object from a YAML file?

level: juniorimportance: must knowfreq 74%

basics

~20 s

kubectl create only makes new objects and fails if the name exists. kubectl replace overwrites an existing object with the whole file. kubectl apply creates or updates by merging the file into the live object and leaves fields it never set alone.

open as a page

In Kubernetes, what are labels, and how do equality-based and set-based label selectors decide which objects match?

level: juniorimportance: must knowfreq 74%

basics

~20 s

Kubernetes labels are key/value pairs on an object's metadata. A label selector lists requirements, all of which must match: equality (=, !=) or set-based (in, notin, exists). Services, ReplicaSets and kubectl use selectors to find objects.

open as a page

In Kubernetes, what happens to a Deployment's ReplicaSets and Pods when you run kubectl delete deployment, and how does --cascade=orphan change that?

level: juniorimportance: must knowfreq 72%

basics

~20 s

kubectl delete deployment removes the Deployment, then the garbage collector deletes its ReplicaSets and their Pods, which point at their owners through ownerReferences. With --cascade=orphan, those references are removed instead, and the ReplicaSets and Pods keep running.

open as a page

How does client-side `kubectl apply` combine the last-applied configuration, the live Kubernetes object and your file to decide what to change?

level: middleimportance: must knowfreq 58%

basics

~20 s

Client-side kubectl apply runs a three-way merge. Fields in your file are set on the live object, fields in the last-applied record but gone from the file are deleted, and fields in neither are left alone.

open as a page

In Kubernetes ObjectMeta, what do the server-populated uid, generation and resourceVersion fields each tell you, and what does generateName do?

level: middleimportance: should knowfreq 42%

basics

~20 s

uid identifies one incarnation of an object, so delete-and-recreate yields a new one. generation counts desired-state changes, resourceVersion changes on every stored write, and generateName makes the server append a random suffix to a name prefix.

open as a page

Why is a Kubernetes Deployment's spec.selector immutable in apps/v1, and how do you change which pods a Deployment selects?

level: middleimportance: should knowfreq 56%

basics

~20 s

A Deployment's spec.selector decides which ReplicaSets and pods it owns. Changing it in place would orphan them or adopt other objects, so apps/v1 rejects the change as immutable. To change it, create a new Deployment and delete the old one.

open as a page

How do Kubernetes ownerReferences, with their controller and blockOwnerDeletion fields, drive the Foreground, Background and Orphan deletion propagationPolicy values?

level: middleimportance: should knowfreq 48%

basics

~20 s

An ownerReference names an owner by kind, name and UID, and the garbage collector deletes a dependent once all its owners are gone. Background deletes the owner first, Foreground waits for blocking dependents, and Orphan detaches them.

open as a page

A team annotates a Kubernetes Deployment expecting its game-session pods to restart, but nothing rolls out. Why, and which annotations actually drive a Deployment's rollouts and revision history?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Only a change to the pod template starts a rollout, so annotations on the Deployment's own metadata never restart pods. Annotations under spec.template.metadata do, which is how kubectl rollout restart works, while deployment.kubernetes.io/revision numbers each rollout.

open as a page

After a clinical-records portal's pipeline switched to `kubectl apply --server-side`, deploys fail with "Apply failed with 1 conflict" on the Kubernetes Deployment's `.spec.replicas`. How do you diagnose and resolve it?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Server-side apply records an owning field manager for every field in managedFields. The pipeline's manifest sets replicas to a value another manager, here the autoscaler writing through the scale subresource, owns with a different value, so the server rejects it.

open as a page

Why would a 7-replica Kubernetes Deployment deleted with kubectl delete --cascade=foreground still exist with a deletionTimestamp twenty minutes later, and how do you unblock it safely?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Its foregroundDeletion finalizer stays until every blocking dependent is gone, and a Pod is usually stuck on an unreachable node or on its own finalizer. Fix that lowest blocker; stripping finalizers by hand skips the cleanup they guard.

open as a page

In Kubernetes, how do strategic merge patch, JSON merge patch and JSON patch differ, as chosen with `kubectl patch --type`?

level: middleimportance: nice to knowfreq 32%

basics

~20 s

JSON merge patch overlays a partial object and replaces any list wholesale. Strategic merge patch overlays one too, but merges lists such as containers by a key. JSON patch is an ordered list of operations on explicit paths.

open as a page

When one pod of a Kubernetes Deployment running a nightly ledger-reconciliation batch misbehaves, how would you use kubectl label to isolate it for debugging, and what happens afterwards?

level: seniorimportance: nice to knowfreq 30%

basics

~20 s

Overwrite a label the ReplicaSet selects on. The ReplicaSet releases the pod and creates a replacement, and a Service that selects on that label stops routing to it. The pod keeps running unmanaged, so you must delete it yourself.

open as a page