Kubeadm Cluster v1.32 to v 1.33 Upgrade

In this article I will show you how to upgrade the Kubeadm Cluster from v1.32 to v1.33. Unlike managed Kubernetes services that handle upgrades automatically, kubeadm requires a hands-on approach to cluster upgrades. You'll manually upgrade each component - from the control plane nodes to worker nodes - using kubeadm commands and package managers.

While this manual process takes more effort than managed solutions, it gives you complete control over the upgrade timing, allows for thorough testing at each step, and helps you understand exactly what's changing in your cluster infrastructure.

So, let's get started…

Environment

  • Kubeadm Cluster
Hostnameat-kubeadm (master node)
Operating SystemUbuntu 22.04 (Jammy)
vCPU4
Memory8 GB
Disk60 GB
Network172.20.20.75
Hostnameat-kubeadm-2 (worker node)
Operating SystemUbuntu 22.04 (Jammy)
vCPU2
Memory4 GB
Disk40 GB
Network172.20.20.76

Preparation/Monitoring Upgrade Process

  1. Create sample apps
# exec on master node
kubectl create deployment nginx-upgrade --image=nginx --replicas=2
kubectl expose deployment nginx-upgrade --port=80 --target-port=80 
kubectl create ingress nginx-upgrade --class=nginx --rule="nginx-upgrade.at.lab/*=nginx-upgrade:80"

nano /etc/hosts
---
172.20.20.75 nginx-upgrade.at.lab
  1. Create script for monitoring apps
# exec on master node
nano monitoring.sh
---
#!/bin/bash

# List of URLs to check
URLS=(
  "http://nginx-upgrade.at.lab"
)

EXPECTED_STATUS=200  # expected HTTP status
INTERVAL=1           # seconds between checks

echo "📡 Starting Ingress monitoring..."
echo "Expected status: $EXPECTED_STATUS"
echo "Check interval: $INTERVAL seconds"
echo "Press Ctrl+C to stop."

while true; do

    for url in "${URLS[@]}"; do
        STATUS_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$url")

        if [ "$STATUS_CODE" -eq "$EXPECTED_STATUS" ]; then
            echo "✅ $(date '+%Y-%m-%d %H:%M:%S') - $url is OK (HTTP $STATUS_CODE)"
        else
            echo "❌ $(date '+%Y-%m-%d %H:%M:%S') - $url returned HTTP $STATUS_CODE"
        fi
    done

    sleep $INTERVAL
done

chmod +x monitoring.sh
  1. Run monitoring script
# exec on master node
./monitoring.sh >> monitoring.log

# other panel/windows
tail -f monitoring.log
kubectl get po -A --watch

Control-plane/Master Node Upgrade

  1. Add kubeadm v1.33 repository
# exec on master node
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' >> /etc/apt/sources.list.d/kubernetes.list
apt update
apt-cache madison kubeadm
  1. Upgrade kubeadm package
# exec on master node
apt-mark unhold kubeadm && \
apt-get update && apt-get install -y kubeadm='1.33.4-1.1' && \
apt-mark hold kubeadm
kubeadm version
  1. Check upgrade plan
# exec on master node
kubeadm upgrade plan
  1. Upgrade control plane
# exec on master node
killall -s SIGTERM kube-apiserver # trigger a graceful kube-apiserver shutdown
sleep 60 # wait a little bit to permit completing in-flight requests
kubeadm upgrade apply v1.33.4 # execute a kubeadm upgrade command

upgrade process

upgrade completed

  1. Upgrade kubelet
# exec on master node
# mark unschedulable 
kubectl drain at-kubeadm --ignore-daemonsets

# upgrade kubelet and kubectl
apt-mark unhold kubelet kubectl && \
apt-get update && apt-get install -y kubelet='1.33.4-1.1' kubectl='1.33.4-1.1' && \
apt-mark hold kubelet kubectl

# restart kubelet
systemctl daemon-reload
systemctl restart kubelet

# mark schedulable
kubectl uncordon at-kubeadm

when mark unschedulable

  1. Verification

Worker Node Upgrade

  1. Add kubeadm v1.33 repository
# exec on worker node
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' >> /etc/apt/sources.list.d/kubernetes.list
apt update
apt-cache madison kubeadm
  1. Upgrade kubeadm package
# exec on worker node
apt-mark unhold kubeadm && \
apt-get update && apt-get install -y kubeadm='1.33.4-1.1' && \
apt-mark hold kubeadm
kubeadm version
  1. Upgrade worker
# exec on worker node
kubeadm upgrade node
  1. Upgrade kubelet
# exec on master node
kubectl drain at-kubeadm-2 --ignore-daemonsets --delete-emptydir-data

# exec on worker node
apt-mark unhold kubelet kubectl && \
apt-get update && apt-get install -y kubelet='1.33.4-1.1' kubectl='1.33.4-1.1' && \
apt-mark hold kubelet kubectl

systemctl daemon-reload
systemctl restart kubelet

# exec on master node
kubectl uncordon at-kubeadm-2

when mark unschedulable/drain node

  1. Verification

when has 1 pod cattle-cluster-agent CLBO, you can delete to trigger that pod running on other nodes

kubectl delete po cattle-cluster-agent-847f4dfc65-8q98s -n cattle-system

Operational Test

  1. Operational test
# exec on master node
kubectl create deployment nginx-aft-upgrade --image=nginx --replicas=1
kubectl expose deployment nginx-aft-upgrade --port=80 --target-port=80 
kubectl create ingress nginx-aft-upgrade --class=nginx --rule="nginx-aft-upgrade.at.lab/*=nginx-aft-upgrade:80"

nano /etc/hosts
---
172.20.20.75 nginx-aft-upgrade.at.lab

  1. Operational test via rancher

Thank You.

0
Subscribe to my newsletter

Read articles from Muhammad Alfian Tirta Kusuma directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Muhammad Alfian Tirta Kusuma
Muhammad Alfian Tirta Kusuma