Kubernetes: patching nodes, control plane and add-ons

Updated November 2026

A Kubernetes cluster has three layers to patch: the Kubernetes components (control plane and kubelet), the operating system on every node, and the add-ons and images running on top. Stay on a supported minor version, take each patch release, and patch nodes one at a time with drain, reboot and uncordon so your applications stay up.

Supported versions and cadence

The Kubernetes project maintains release branches for the three most recent minor versions. Each gets about 14 months of patches: 12 months of standard support, then 2 months of maintenance mode. Patch releases normally come out monthly, with urgent releases in between when needed. Security fixes may be backported to the three supported branches, depending on severity and feasibility.

Kubernetes minor versions as of November 2026
VersionEnd of life
1.37October 28, 2027
1.36June 28, 2027
1.35February 28, 2027 (maintenance mode from December 28, 2026)
1.34Ended October 27, 2026
1.33 and olderEnded

The next planned patch releases target November 10 and December 15, 2026. Check your versions:

kubectl version
kubectl get nodes -o wide    # kubelet VERSION, OS-IMAGE, KERNEL-VERSION, CONTAINER-RUNTIME

The version skew policy sets the order of every upgrade:

Control plane upgrades with kubeadm

For a patch release (1.37.1 to 1.37.2) you just install newer packages. For a minor upgrade, first point the pkgs.k8s.io repository at the new minor version: change v1.36 to v1.37 in /etc/apt/sources.list.d/kubernetes.list or /etc/yum.repos.d/kubernetes.repo. Back up etcd before you start. Then, on the first control plane node (Debian/Ubuntu shown; replace x with the newest patch):

sudo apt-get update
apt-cache madison kubeadm               # find the newest 1.37.x
sudo apt-mark unhold kubeadm && \
sudo apt-get install -y kubeadm='1.37.x-*' && \
sudo apt-mark hold kubeadm
kubeadm version
sudo kubeadm upgrade plan               # checks the cluster, lists target versions
sudo kubeadm upgrade apply v1.37.x      # restarts control plane components

On RHEL, Fedora and other DNF5 systems use sudo dnf install -y kubeadm-'1.37.x-*' --setopt=disable_excludes=kubernetes (with DNF4, --disableexcludes=kubernetes). After apply, upgrade your CNI network plugin following its own instructions. On the other control plane nodes run sudo kubeadm upgrade node instead of apply, one node at a time. kubeadm upgrades CoreDNS and kube-proxy once the last control plane node is done, and renews the certificates it manages.

Then, on each control plane node, upgrade the kubelet. This restarts the kubelet:

kubectl drain cp1 --ignore-daemonsets
sudo apt-mark unhold kubelet kubectl && \
sudo apt-get install -y kubelet='1.37.x-*' kubectl='1.37.x-*' && \
sudo apt-mark hold kubelet kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
kubectl uncordon cp1

Worker nodes follow the same pattern: upgrade kubeadm, run sudo kubeadm upgrade node, drain, upgrade the kubelet, restart it, uncordon. Finish with kubectl get nodes: every node should be Ready with the new version. If kubeadm upgrade fails halfway, you can run it again; kubeadm keeps backups of etcd data and static Pod manifests in /etc/kubernetes/tmp.

Node OS patching: drain and reboot

Kernel, glibc, OpenSSL, containerd and runc fixes come from the node's own distribution. Patch each node like any server (see Linux), but move its workloads away first.

1. Cordonno new pods 2. Drainevict, obey PDBs 3. Patchand reboot 4. Uncordoncheck Ready next node, one at a time
kubectl drain does steps 1 and 2; kured can run the whole cycle for you.
kubectl drain node1 --ignore-daemonsets --delete-emptydir-data --timeout=15m
# on node1:
sudo apt-get update && sudo apt-get upgrade -y
sudo reboot                                # reboots the node
# when it is back:
kubectl uncordon node1
kubectl get node node1

drain cordons the node (marks it unschedulable), then evicts its pods, honoring PodDisruptionBudgets and each pod's grace period. What the flags mean:

The held packages (apt-mark hold) and the exclude= line in kubernetes.repo keep a normal OS upgrade from changing kubeadm, kubelet and kubectl behind your back. kubectl cordon node1 on its own only stops new pods; existing ones keep running. Patch one node at a time, or a few, never more than your spare capacity allows. For many nodes, see patching many servers.

Automate reboots with kured

kured (Kubernetes Reboot Daemon) is a DaemonSet that reboots nodes safely when the OS says a reboot is needed. It checks every 60 minutes for /var/run/reboot-required or a sentinel command, takes a lock in the API server so only one node reboots at a time, cordons and drains the node first, and uncordons it afterwards. It can wait while Prometheus alerts are active or while selected pods run, and it can be limited to a time window with --reboot-days, --start-time, --end-time and --time-zone. On RHEL-family nodes, kured's docs suggest the sentinel command sh -c "! needs-restarting --reboothint".

# kured 1.23.0 targets Kubernetes 1.35-1.37
kubectl apply -f https://github.com/kubereboot/kured/releases/download/1.23.0/kured-1.23.0-combined.yaml

kured only reboots. Nodes still need automatic updates to install packages (automatic updates). Keep the default of one node at a time; kured's docs call concurrent reboots unsafe for production. Alert on its kured_reboot_required metric so a stuck reboot doesn't go unnoticed.

PodDisruptionBudgets keep apps up

A PodDisruptionBudget (PDB) limits how many pods of an app voluntary disruptions, such as a drain, may take down at once. It does not protect against a node crashing.

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: web-pdb
spec:
  maxUnavailable: 1
  unhealthyPodEvictionPolicy: AlwaysAllow
  selector:
    matchLabels:
      app: web

With 3 replicas and maxUnavailable: 1, a drain evicts one web pod, waits until a replacement is healthy elsewhere, then continues. AlwaysAllow lets drains evict pods that are already broken (for example in CrashLoopBackOff), which Kubernetes recommends.

Budgets that block patching. maxUnavailable: 0, or minAvailable equal to the replica count, allows zero evictions, so a drain never finishes. The same happens with a single-replica app. Run kubectl get pdb -A before patching: an ALLOWED DISRUPTIONS value of 0 means drains will wait.

Patch add-ons and images

Ingress controllers
They face the internet, so patch them first. Ingress NGINX is retired: maintenance stopped in March 2026 and its repository was archived on March 24, 2026, so new vulnerabilities will not be fixed. Several 2026 CVEs, such as configuration injection flaws CVE-2026-3288 and CVE-2026-4342, hit it. Check with kubectl get pods --all-namespaces --selector app.kubernetes.io/name=ingress-nginx and migrate to Gateway API or another maintained controller.
CNI (network plugin)
kubeadm does not upgrade it. Follow the plugin's own upgrade notes after the control plane upgrade.
CSI (storage drivers)
They release separately and get CVEs too, for example CVE-2026-3864 in the NFS CSI driver and CVE-2026-3865 in the SMB CSI driver. List what you run and track each driver's releases.
Helm charts and images
helm list -A shows chart versions. Application images are patched by rebuilding; see patching containers.

Managed clusters (EKS, GKE, AKS)

The provider patches the control plane. Nodes and add-ons are still partly or fully your job.

Provider support windows differ from upstream: EKS still offers 1.34 in standard support until December 2, 2026, after upstream ended it.

Kubernetes security announcements

Sources