Skip to main content
RunBook Academy

KubernetesVI · kubectl for Administratorskubectl for administrators

kubectl edit, label, annotate, set — in-place modification

Intermediate⏱ ~16 minkubectl

What you'll learn

  • Use kubectl edit to modify a live object through your $EDITOR
  • Use kubectl label and kubectl annotate to manage object metadata
  • Use kubectl set to change images, resources, and env on Deployments and other workloads
  • Recognise when in-place edits bypass GitOps and what to do about it

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

Read commands answer questions. Write commands change state. This lesson covers the four in-place write commands every operator reaches for: edit, label, annotate, set. They are fast, ergonomic, and the source of most cluster drift.

kubectl edit — open the object in your editor

kubectl edit reads the object from the API server, opens it in your $EDITOR ($KUBE_EDITOR overrides), and applies the edited YAML on save. Under the hood it does a GET then a PUT (not a PATCH) — the entire object is replaced.

kubectl edit deployment web -n team-a-prod
kubectl edit svc web -o yaml
KUBE_EDITOR='vim' kubectl edit pod web-7c8

The behaviour:

  1. kubectl reads the object (or subresource with -o yaml).
  2. kubectl writes it to a temp file and runs $KUBE_EDITOR (or $EDITOR) on it.
  3. On save, kubectl PUTs the edited YAML back to the API server.
  4. The API server validates the YAML; if it parses, the object is replaced.

Important properties:

  • The edit is a PUT, not a PATCH. If you delete a field by accident, the PUT replaces the whole object and the field is gone.
  • The edit runs against whatever the API server returns. Server-defaulted fields (e.g., status, default labels) appear in the file and are sent back unchanged.
  • edit is interactive. Non-interactive edits require different commands.
# Non-interactive edit via stdin
kubectl get deployment web -o yaml | sed 's/replicas: 3/replicas: 5/' | kubectl apply -f -

# Or use kubectl scale (cleaner for single-field changes)
kubectl scale deployment web --replicas=5

kubectl label — manage labels

Labels are how Kubernetes objects get selected. Setting them right is what makes selectors, services, and replication controllers work.

kubectl label pods web-7c8 app=web                            # set
kubectl label pods web-7c8 app=web --overwrite                # set if exists
kubectl label pods web-7c8 app-                               # remove (key-)
kubectl label pods -l app=web env=prod                        # all matching
kubectl label --all pods env=prod                             # all in ns
kubectl label node node-3 team=web                            # on a Node
kubectl label ns team-a-prod pod-security.kubernetes.io/enforce=restricted

The trailing - syntax removes a label. app- deletes the label with key app. This is unique to kubectl; the API server itself does not understand app-.

--overwrite is required to change an existing label. Without it, kubectl returns “already has that value” or refuses to overwrite (depending on the version).

Production patterns

The labels that matter most:

# Recommended labels (see Kubernetes recommended labels)
kubectl label ... app.kubernetes.io/name=web
kubectl label ... app.kubernetes.io/instance=web-7c8
kubectl label ... app.kubernetes.io/version=1.2.3
kubectl label ... app.kubernetes.io/component=frontend
kubectl label ... app.kubernetes.io/part-of=checkout
kubectl label ... app.kubernetes.io/managed-by=helm

# Node labels for scheduling
kubectl label node node-3 workload=high-memory
kubectl label node node-3 workload=high-memory-   # remove

A node label with a - suffix removes that label. The kubelet will not delete labels applied through its own Node API; labels on Nodes are operator-managed.

kubectl annotate — manage annotations

Annotations are non-identifying metadata. They are used for tooling, documentation, and arbitrary key-value storage.

kubectl annotate pods web-7c8 description="production web tier"
kubectl annotate pods -l app=web contact=team-a@example.com
kubectl annotate pods web-7c8 description-                      # remove
kubectl annotate pods web-7c8 description="updated text" --overwrite

Common production uses:

  • kubernetes.io/ingress.class (legacy) — class for Ingress
  • service.beta.kubernetes.io/aws-load-balancer-type — cloud LB integration
  • prometheus.io/scrape=true — Prometheus scrape annotations
  • sidecar.istio.io/inject=false — service mesh overrides
  • config.kubernetes.io/local-config — kubectl config hint

Annotations are strings; they cannot be selected by label selector. Use them for tooling, not for identification.

kubectl set — modify workload specs

kubectl set is a family of subcommands that wrap PATCH operations on workload specs:

# Set image on Deployment (rolls out a new ReplicaSet)
kubectl set image deployment/web web=nginx:1.27.2
kubectl set image deployment/web web=nginx:1.27.2 --record

# Set environment variables
kubectl set env deployment/web DB_HOST=db.example.com
kubectl set env deployment/web DB_HOST-                # remove var
kubectl set env deployment/web --from=configmap/web     # from ConfigMap
kubectl set env deployment/web --from=secret/db         # from Secret

# Set resource requests/limits
kubectl set resources deployment/web -c web \
  --requests=cpu=200m,memory=256Mi --limits=cpu=500m,memory=512Mi

# Set service account
kubectl set serviceaccount deployment/web app-sa

# Set pull policy / image pull secrets
kubectl set image deployment/web web=nginx:1.27.2
kubectl set image-registries ...                          # in newer versions

kubectl set is the right tool for one-off changes that should propagate through the workload’s rollout machinery. The Deployment controller detects the spec change and rolls out a new ReplicaSet.

When in-place editing breaks GitOps

The fundamental tension: a Kubernetes cluster’s live state and the manifests in source control can diverge. apply makes them converge toward the manifest. edit, label, annotate, set make the live state diverge from the manifest.

flowchart LR
    A[Manifest in Git] -->|apply| B[Live state]
    B -->|edit / set / label| A
    A -.->|next apply| B

Production discipline:

  • Triage edits are temporary. A kubectl edit to fix a typo or update an image tag during an incident is fine. Fix Git immediately afterwards.
  • Sustained changes go through Git. Anything that should persist for hours, days, or weeks must be in a manifest that apply will reapply.
  • Audit live vs Git regularly. kubectl diff -f manifest.yaml shows the divergence. Use it in CI: if the diff is non-empty, fail the build.
  • Use --server-side apply (Part VII) for fields that multiple tools need to manage without overwriting each other.

How to safely do a one-off edit

If you must edit (or set) in production:

# 1. Capture the current state
kubectl get deployment web -o yaml > /tmp/web-before.yaml

# 2. Make the edit
kubectl edit deployment web

# 3. Verify the change took
kubectl get deployment web -o yaml | diff - /tmp/web-before.yaml

# 4. Reflect the change in Git
# (commit the change to the manifest repo)

# 5. If something went wrong, restore from the backup
kubectl apply -f /tmp/web-before.yaml

The backup before the edit is the difference between a clean recovery and a manual reconstruction. Production operators keep /tmp/<object>-before.yaml snapshots for every edit session.

Cross-course references

  • The Terraform course part XVII-Terraform-Drift covers drift detection in Terraform state; the same discipline applies to live Kubernetes state vs manifests in Git.
  • The Ansible course part XXXVI-Ansible-Drift covers configuration drift; kubectl edit is the live equivalent of running an ad-hoc shell command.
  • The Linux course part LXXIV-Linux-Drift covers configuration management drift at the OS level.

Quiz

Knowledge check · 4 questions

  1. Q1. Which HTTP verb does `kubectl edit` use when it saves the edited object?

  2. Q2. `kubectl label pods web-7c8 app-` removes the label with key `app` from the Pod.

  3. Q3. An incident requires immediately rolling the web Deployment from `nginx:1.27.1` to `nginx:1.27.2` to pick up a security patch. The on-call engineer uses `kubectl set image`. What happens to GitOps, what is the blast radius, and how do you reconcile afterwards?

    Cluster has 30+ workloads, all managed by ArgoCD from a Git repository. The web Deployment is in repo `infra-manifests`. The current image is `nginx:1.27.1`. The new image is `nginx:1.27.2`. The Deployment has 5 replicas. ArgoCD is configured with `prune: false` and is the source of truth.

  4. Q4. Explain why `kubectl set image` creates drift and how to reconcile after a triage edit.

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Prefer apply -f over edit for sustained changes. apply is manifest-driven and reproducible; edit is interactive and creates drift.
  • Reserve edit for triage. A 2am fix to a typo or an emergency image bump is fine. Anything that should persist longer than the incident must be reflected in Git.
  • Capture the object before every edit. kubectl get -o yaml > /tmp/before.yaml is the difference between a clean recovery and a manual reconstruction.
  • Use kubectl diff -f manifest.yaml in CI. If a manifest has drifted from the live state, fail the build.
  • Audit pods/exec, pods/eviction, and other write verbs. In a GitOps cluster, only the controller should write. Any manual write is an exception that needs review.