Kustomize labels and commonLabels
The labels field adds a set of labels to every resource, optionally extending selectors as well.
Common labels are how you tag a whole overlay with app, environment, or team. The newer labels field controls whether selectors are touched, avoiding a classic upgrade trap.
What it does
commonLabels adds labels to every resource metadata and also injects them into selectors and pod templates. The newer labels field does the same but lets you set includeSelectors and includeTemplates per entry, so you can add metadata labels without mutating immutable selectors.
Common usage
# newer form: metadata only, leave selectors alone
labels:
- pairs:
app.kubernetes.io/part-of: storefront
env: prod
includeSelectors: false
# older form (also touches selectors and templates)
commonLabels:
app: myappFields
| Field | What it does |
|---|---|
| commonLabels | Add labels to metadata, selectors, and templates |
| labels[].pairs | Map of labels to add (newer field) |
| labels[].includeSelectors | Whether to also add to selectors (default false) |
| labels[].includeTemplates | Whether to also add to pod template labels |
In CI
Selectors on Deployments and Services are immutable after creation. Adding a label via commonLabels (which edits selectors) to an existing Deployment makes kubectl apply fail. Prefer labels with includeSelectors: false for new metadata on already-deployed workloads.
Common errors in CI
"field is immutable" or "spec.selector: Invalid value ... field is immutable" at apply time means a label change reached a Deployment or Service selector. Use the labels field with includeSelectors: false. If pods stop matching a Service, the opposite happened: a selector changed but pod labels did not, or vice versa.
Using this in CI
A runner has no kubeconfig, no cached context, and no interactive auth. Every kubectl invocation in CI needs the context supplied explicitly, and most confusing CI failures here are the command running against the wrong cluster or no cluster at all.
# never rely on the ambient context on a runner
kubectl --context "$KUBE_CONTEXT" -n "$NAMESPACE" get pods
# confirm what you are actually connected to before mutating anything
kubectl config current-context
kubectl cluster-info
# fail fast instead of hanging on an unreachable API server
kubectl --request-timeout=30s get nodes