kubectl annotate: Command Reference for CI/CD
Attach metadata that tools read but selectors ignore.
kubectl annotate sets free-form key/value metadata that controllers and tooling read but selectors never match. Its headline CI use is the change-cause annotation that makes rollout history meaningful. This reference covers the syntax and limits.
Common flags and usage
- annotate <res> <name> k=v: add an annotation
- annotate <res> <name> k-: remove an annotation
- --overwrite: replace an existing annotation (required for re-runs)
- -l / --all: annotate many objects at once
- No value-format rules, but a 256 KB total payload cap
Example
kubectl annotate deploy/web \
kubernetes.io/change-cause="deploy ${GIT_SHA}" --overwrite
kubectl annotate svc/web prometheus.io/scrape="true" --overwriteIn CI
Set change-cause on each deploy so kubectl rollout history shows which revision was what. Like label, re-running without --overwrite fails. The annotations payload is capped at 256 KB; client-side apply stores last-applied-configuration there, so very large manifests should use --server-side apply.
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 nodesKey takeaways
- change-cause is the annotation that makes rollout history readable.
- Annotations have no format rules but a 256 KB total cap.
- Add --overwrite for idempotent re-runs, same as label.