How to Upgrade Kubeadm Kubernetes Clusters The Fast Way


My home lab Kubernetes cluster built with kubeadm hasn’t got an upgrade for a while, still at 1.29 which was first released roughly 2 years ago. And the latest is 1.33 already. According to the official kubeadm docs

Skipping MINOR versions when upgrading is unsupported. 

Which basically says, if you try to upgrade from 1.29 to 1.31 or newer directly, you’re on your own 🙂 But I really don’t want to repeat myself and upgrade the whole cluster a few times… After some reading on the version skew policy, I noticed

kubelet may be up to three minor versions older than kube-apiserver (kubelet < 1.25 may only be up to two minor versions older than kube-apiserver).

Example:

  • kube-apiserver is at 1.30
  • kubelet is supported at 1.301.291.28, and 1.27

Looks like I can upgrade the control-plane 3 times at most, eg, 1.29 -> 1.30, 1.30 -> 1.31, 1.31 -> 1.32, then I can upgrade the nodes from 1.29 to 1.32 directly? Because the node upgrade is simple as

# from local where I have kubectl access
$ k drain <node-name> --ignore-daemonsets --delete-emptydir-data

# on the node
# the signing key
$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.32/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# the new repo
$ echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.32/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# install the new version
$ sudo apt update && sudo apt install -y kubelet kubectl
# restart kubelet service
$ sudo systemctl restart kubelet

# from local
$ k uncordon <node-name>

Sounds like a plan! Now to test it out.

First I upgraded the control-plane 1 minor version at a time, following the upgrade instructions here. After 3 iterations, my cluster looks like this:

$ k get nodes
NAME       STATUS   ROLES           AGE    VERSION
cosmos     Ready    <none>          171d   v1.29.5
kmaster2   Ready    control-plane   636d   v1.32.4
knode3     Ready    <none>          635d   v1.29.5
knode7     Ready    <none>          635d   v1.29.5
knode8     Ready    <none>          636d   v1.29.5

Then I upgraded each node from 1.29 to 1.32 in 1 step. And ta-da!

$ k get nodes
NAME       STATUS   ROLES           AGE    VERSION
cosmos     Ready    <none>          171d   v1.32.4
kmaster2   Ready    control-plane   636d   v1.32.4
knode3     Ready    <none>          635d   v1.32.4
knode7     Ready    <none>          635d   v1.32.4
knode8     Ready    <none>          636d   v1.32.4

🙂