Skip to main content
This guide walks through a safe, kubeadm-supported upgrade of a small Kubernetes cluster (control plane + one worker) without provisioning new VMs and with minimal impact to users. The strategy is to upgrade nodes one at a time while keeping workloads available by leveraging Kubernetes scheduling. Key goals:
  • No new VMs.
  • No downtime for user-facing applications.
  • Follow kubeadm-supported upgrade paths (upgrade kubeadm first when changing minor versions).
Before upgrading a control plane node to a newer minor version, update the local kubeadm package to the target minor version (for example, 1.20.x) and verify the upgrade plan with kubeadm upgrade plan.

Prerequisites and constraints

Quick reference: upgrade strategy (summary)

1) Inspect the cluster

Start by listing nodes and observing where workloads run. Create a short alias if you like:
Example output:
Check for node taints to confirm schedulability:
List deployments and pods to see application distribution:
Note: In this lab the application pods are distributed across controlplane and node01. Because the control plane is schedulable, you can move workloads between nodes during the upgrade.

2) Choose an upgrade strategy

Constraints to respect:
  • Only two VMs (no extra capacity).
  • Applications must remain available.
Strategy:
  • Upgrade nodes one at a time. Drain a node and let Kubernetes reschedule pods onto the other node.
  • Never upgrade all nodes simultaneously.

3) Check what kubeadm can upgrade to

On the control plane node (or wherever kubeadm is installed), run:
This outputs the recommended target versions that the current kubeadm binary supports and explains whether you must update kubeadm first (required when moving to a newer minor version). Example excerpt:
This tells you whether you can upgrade in-place or if you need to update the kubeadm package first to follow the kubeadm-supported path (for minor bumps).

4) Consult the official docs and pick the exact target

Follow the official guide: Upgrading kubeadm clusters.
A screenshot of a Kubernetes documentation webpage titled "Upgrading kubeadm clusters," showing upgrade instructions and links with a left navigation menu. A blue banner at the top notes the Dockershim removal for Kubernetes 1.24.
From the docs:
  • Select the supported upgrade path (e.g., 1.19 → 1.20).
  • Determine the exact patch package to install (e.g., 1.20.0-00 or latest 1.20.x-00 available from apt).
On Debian/Ubuntu, find available kubeadm versions:
Confirm OS release if needed:

5) Control plane node upgrade (step-by-step)

High-level steps:
  1. Drain and cordon the control plane node (move regular workloads off).
  2. Upgrade kubeadm on the control plane to the target minor version (e.g., 1.20.x-00).
  3. Run kubeadm upgrade apply v1.20.0 (or chosen patch).
  4. Upgrade kubelet and kubectl.
  5. Restart kubelet and uncordon the control plane node.
Important: always use --ignore-daemonsets when draining so DaemonSet-managed pods do not block eviction.
Upgrade the kubeadm package on the control plane to the target minor version before running kubeadm upgrade apply when moving across minor versions (for example 1.19 → 1.20). Failing to do so will prevent the upgrade.

5.1 Drain the control plane node

From your management shell:
Sample output:
Verify the node is cordoned:
Confirm application pods now run on node01.

5.2 Upgrade kubeadm on the control plane node

SSH into controlplane and update kubeadm to the chosen patch. Replace 1.20.0-00 with your selected patch:

5.3 Apply the control plane upgrade

Run the upgrade apply command on the control plane:
What this does:
  • Updates control plane static pods: kube-apiserver, kube-controller-manager, kube-scheduler.
  • Writes new kubelet config and creates a kubelet-config-1.20 ConfigMap.
  • Updates required cluster addons (e.g., CoreDNS, kube-proxy) if needed.
Success message example:

5.4 Upgrade kubelet and kubectl on the control plane

Still on controlplane, install matching kubelet and kubectl packages:
Verify node version from your management shell:

5.5 Uncordon the control plane node

Make the control plane schedulable again:
Control plane is now running v1.20.0 and can host pods again.

6) Worker node upgrade (node01)

Repeat similar steps for each worker node, one at a time. High-level worker steps:
  1. Drain the worker (--ignore-daemonsets).
  2. Upgrade kubeadm on the worker.
  3. Run sudo kubeadm upgrade node on the worker to update node kubelet config.
  4. Upgrade kubelet and kubectl.
  5. Restart kubelet and uncordon the worker.

6.1 Drain node01

From the control plane or management shell:
Verify pods moved to controlplane:

6.2 Upgrade kubeadm on node01

SSH to node01 (or use its internal IP discovered with kubectl get nodes -o wide) and run:
kubeadm upgrade node updates kubelet configuration and supporting files on the worker to match the upgraded control plane.

6.3 Upgrade kubelet and kubectl on node01

Still on node01:
Return to the control plane and uncordon node01:
Expected final output:

7) Final checks and validation

  • Ensure all pods are Running and Ready:
  • Verify cluster components and API health:
  • Check addons and CNI plugin compatibility. Consult the CNI plugin docs for any required post-upgrade steps (for example, Flannel, Calico, Weave).
  • Validate application-level availability by exercising endpoints or load balancers.

Troubleshooting tips

  • If kubeadm upgrade plan reports incompatible versions, do not proceed—consult kubeadm docs for the supported path.
  • Use kubectl describe pod <pod> and kubectl logs <pod> for pod-level failures.
  • If kubelet fails after restart, inspect journalctl -u kubelet on the node.

Summary

  • Inspected the cluster and confirmed two schedulable nodes on v1.19.0.
  • Upgraded the control plane first: drained, upgraded kubeadm, ran kubeadm upgrade apply v1.20.0, then upgraded kubelet/kubectl.
  • Upgraded the worker next: drained, upgraded kubeadm, ran kubeadm upgrade node, then upgraded kubelet/kubectl.
  • After uncordoning each node, both nodes show Ready at v1.20.0 and user workloads remained available throughout the process.
Congratulations — your cluster has been upgraded with minimal impact to workloads.

Watch Video