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
Hostname | at-kubeadm (master node) |
Operating System | Ubuntu 22.04 (Jammy) |
vCPU | 4 |
Memory | 8 GB |
Disk | 60 GB |
Network | 172.20.20.75 |
Hostname | at-kubeadm-2 (worker node) |
Operating System | Ubuntu 22.04 (Jammy) |
vCPU | 2 |
Memory | 4 GB |
Disk | 40 GB |
Network | 172.20.20.76 |
Preparation/Monitoring Upgrade Process
- 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
- 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
- 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
- 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
- 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
- Check upgrade plan
# exec on master node
kubeadm upgrade plan
- 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
- 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
- Verification
Worker Node Upgrade
- 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
- 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
- Upgrade worker
# exec on worker node
kubeadm upgrade node
- 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
- 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
- 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
- Operational test via rancher
Thank You.
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
