Upgrading clusters and draining nodes
Upgrade a kubeadm cluster one minor version at a time: first the control plane with kubeadm upgrade apply, then every other node, drained, upgraded and put back to work.
Key ideas in this lesson · tap one for a simple explanation
What you will be able to do
- Say which versions may run side by side (the version skew rules) and why they decide the upgrade order.
- Upgrade the first control plane with kubeadm upgrade plan and apply, then its kubelet and kubectl.
- Drain, upgrade and uncordon nodes one at a time, and say what each drain flag is for.
An upgrade moves the cluster to a newer Kubernetes version, for example from 1.36 to 1.37. With it is a fixed list of about fifteen commands. The exam punishes small slips in that list: a package not pinned to a version, a never restarted, a left cordoned.
This lesson gives you the list and the reason for each step. Then you practice the part kind can do for real: draining a node and putting it back. It belongs to the exam topic Manage the lifecycle of Kubernetes clusters.
First control plane
upgrades the control plane
kubeadm upgrade apply
Other control planes
only if you have more than one
kubeadm upgrade node
Each worker, one at a time
drain, upgrade, uncordon
kubeadm upgrade node
Nothing may be newer than the API server, so the control plane always goes first. Then one node at a time.
Version skew decides the order
During an upgrade, parts of the cluster run different versions for a while. This is called version skew. The rules say how far apart the versions may be, measured against the :
Example: the API server runs 1.37. A kubelet on 1.34 is allowed. A kubelet on 1.38 is not. Two rules follow from the table:
- The control plane goes first, because nothing may be newer than the API server.
- One minor version per upgrade. 1.36 to 1.37 works. 1.35 straight to 1.37 is refused. Skipping patch releases is fine, for example 1.36.2 straight to 1.37.1.
One more thing: the VERSION column of kubectl get nodes shows each node's kubelet version. It changes only after you upgrade and restart the kubelet on that node. kubeadm upgrade apply alone never changes it.
Upgrade the first control plane
Run these on the first control plane node, as root. The example moves from v1.36 to v1.37.1. The same steps repeat on every node, so learn their shape once:
1. Switch the repository
point apt at v1.37
2. New kubeadm
unhold, install the exact version, hold
3. kubeadm upgrade
apply on the first control plane, node everywhere else
4. New kubelet
drain, install kubelet and kubectl, restart, uncordon
# exam: ssh <control-plane>; sudo -i
# root may need: export KUBECONFIG=/etc/kubernetes/admin.conf
# 1. Point apt at the new minor version and find the exact package
sed -i 's#/v1.36/#/v1.37/#' /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-cache madison kubeadm | head -3 # e.g. 1.37.1-1.1
# 2. kubeadm first
apt-mark unhold kubeadm
apt-get install -y kubeadm=1.37.1-1.1
apt-mark hold kubeadm
kubeadm version -o short # v1.37.1
# 3. Plan, then apply exactly the version you installed
kubeadm upgrade plan
kubeadm upgrade apply v1.37.1 # -y skips the confirmation prompt
# 4. kubelet and kubectl, with the node drained
kubectl drain <control-plane> --ignore-daemonsets
apt-mark unhold kubelet kubectl
apt-get install -y kubelet=1.37.1-1.1 kubectl=1.37.1-1.1
apt-mark hold kubelet kubectl
systemctl daemon-reload
systemctl restart kubelet
kubectl uncordon <control-plane>
kubectl get nodeskubeadm upgrade apply upgrades the control plane , renews their certificates, and upgrades and kube-proxy. It does not touch the kubelet. That is step 4 in the block above.
Other control planes and the workers
Every other node gets the same package steps. The one difference: run kubeadm upgrade node instead of upgrade apply.
# Additional control plane nodes: the same package steps, but instead of "upgrade apply":
kubeadm upgrade node
# Each worker. On the worker (ssh <worker>; sudo -i):
sed -i 's#/v1.36/#/v1.37/#' /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-mark unhold kubeadm && apt-get install -y kubeadm=1.37.1-1.1 && apt-mark hold kubeadm
kubeadm upgrade node
# Wherever kubectl has admin credentials:
kubectl drain <worker> --ignore-daemonsets --delete-emptydir-data
# Back on the worker:
apt-mark unhold kubelet kubectl && apt-get install -y kubelet=1.37.1-1.1 kubectl=1.37.1-1.1 && apt-mark hold kubelet kubectl
systemctl daemon-reload && systemctl restart kubelet
# And from the admin side again:
kubectl uncordon <worker>
kubectl get nodeskubeadm upgrade node reads the target version from the cluster, so it takes no version number. Never run upgrade apply a second time on the other control planes. Upgrade the nodes one at a time, so the rest of the cluster keeps your apps running.
cordon, drain, uncordon
Before you restart a node's kubelet, move its Pods somewhere else. Example: cka-worker2 runs three web Pods. kubectl drain cka-worker2 evicts them, and their starts new copies on the other workers. After the upgrade, kubectl uncordon cka-worker2 opens the node again.
In the official docs· open on exam day too
- Upgrading kubeadm clusterssearch: kubeadm upgrade
- Version Skew Policysearch: version skew policy
- Safely Drain a Nodesearch: drain node
- Changing The Kubernetes Package Repositorysearch: change package repository
Upgrade a kubeadm cluster by one minor version
cp1 and worker w1, both on Kubernetes v1.36 and installed from pkgs.k8s.io. Upgrade the control plane components, kubelets and kubectl on both nodes to the newest v1.37 patch release available. Upgrade one node at a time, drain each node before upgrading its kubelet, and leave both nodes schedulable. You work from cp1; ssh w1 reaches the worker.Runs on a kubeadm cluster (VM lab), not on the kind lab.
- 1
Start from a healthy lab
No setup needed for this one.
- 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-upgrade-1/verify | bashGot FAIL? Read which check failed, fix it, run it again.
Drain a node for maintenance
cka-worker2 is going down for maintenance. Make sure no new Pods can be scheduled onto it, and empty it of every Pod except those managed by DaemonSets. The Pods of Deployment web in namespace ar-drain keep scratch data in an emptyDir volume; that data may be discarded. Any Pod on the node that no controller manages is a leftover test Pod and may be deleted. Leave the node unschedulable, since the maintenance team will return it to service themselves.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-upgrade-2/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-upgrade-2/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/ar-upgrade-2/cleanup | bash
Finished this lesson?
0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.