K8s kubeadm Upgrade: Step-by-Step Guide
Upgrade Kubernetes clusters with kubeadm from one minor version to the next. Control plane upgrade, worker node drain, kubelet upgrade, and rollback procedures.
π‘ Quick Answer: Upgrade kubeadm first:
apt-get install kubeadm=1.30.0-*. Thenkubeadm upgrade planto verify,kubeadm upgrade apply v1.30.0on the first control plane node. Drain each node, upgrade kubelet + kubectl, restart kubelet, uncordon. Always upgrade one minor version at a time (1.28β1.29β1.30, never 1.28β1.30). Backup etcd before starting.
The Problem
Kubernetes releases every 4 months. Staying current means:
- Security patches and CVE fixes
- New features and API versions
- Avoiding unsupported versions (N-3 policy)
- Zero-downtime upgrades for production workloads
The Solution
Pre-Upgrade Checklist
# 1. Check current version
kubectl version
kubeadm version
kubelet --version
# 2. Check upgrade path
kubeadm upgrade plan
# 3. Backup etcd
ETCDCTL_API=3 etcdctl snapshot save /backup/pre-upgrade-$(date +%Y%m%d).db \
--endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
# 4. Read release notes for breaking changes
# https://kubernetes.io/releases/
# 5. Check deprecated APIs
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apisUpgrade Control Plane (First Node)
# Step 1: Upgrade kubeadm
apt-get update
apt-get install -y --allow-change-held-packages kubeadm=1.30.0-1.1
# Verify
kubeadm version
# kubeadm version: v1.30.0
# Step 2: Check upgrade plan
kubeadm upgrade plan
# Shows: available versions, component versions, warnings
# Step 3: Apply upgrade
kubeadm upgrade apply v1.30.0
# Upgrades: kube-apiserver, kube-controller-manager,
# kube-scheduler, kube-proxy, CoreDNS, etcd
# Step 4: Drain the control plane node
kubectl drain control-plane-1 --ignore-daemonsets --delete-emptydir-data
# Step 5: Upgrade kubelet and kubectl
apt-get install -y --allow-change-held-packages \
kubelet=1.30.0-1.1 \
kubectl=1.30.0-1.1
# Step 6: Restart kubelet
systemctl daemon-reload
systemctl restart kubelet
# Step 7: Uncordon
kubectl uncordon control-plane-1
# Verify
kubectl get nodes
# control-plane-1 Ready control-plane v1.30.0Upgrade Additional Control Plane Nodes
# On each additional control plane node:
# Step 1: Upgrade kubeadm
apt-get install -y --allow-change-held-packages kubeadm=1.30.0-1.1
# Step 2: Upgrade node (NOT "apply" β only first node uses apply)
kubeadm upgrade node
# Step 3: Drain
kubectl drain control-plane-2 --ignore-daemonsets --delete-emptydir-data
# Step 4: Upgrade kubelet + kubectl
apt-get install -y --allow-change-held-packages \
kubelet=1.30.0-1.1 \
kubectl=1.30.0-1.1
systemctl daemon-reload
systemctl restart kubelet
# Step 5: Uncordon
kubectl uncordon control-plane-2Upgrade Worker Nodes
# On each worker node:
# Step 1: Upgrade kubeadm
apt-get install -y --allow-change-held-packages kubeadm=1.30.0-1.1
# Step 2: Upgrade node config
kubeadm upgrade node
# Step 3: Drain from control plane
kubectl drain worker-1 --ignore-daemonsets --delete-emptydir-data
# Step 4: Upgrade kubelet + kubectl
apt-get install -y --allow-change-held-packages \
kubelet=1.30.0-1.1 \
kubectl=1.30.0-1.1
systemctl daemon-reload
systemctl restart kubelet
# Step 5: Uncordon from control plane
kubectl uncordon worker-1Verify Upgrade
# All nodes on new version
kubectl get nodes
# NAME STATUS ROLES VERSION
# control-plane-1 Ready control-plane v1.30.0
# control-plane-2 Ready control-plane v1.30.0
# worker-1 Ready <none> v1.30.0
# worker-2 Ready <none> v1.30.0
# All system pods healthy
kubectl get pods -n kube-system
# Check component versions
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.kubeletVersion}{"\n"}{end}'Upgrade Order Summary
1. Backup etcd β CRITICAL
2. Upgrade kubeadm on first control plane
3. kubeadm upgrade apply v1.X.Y β Only on first CP
4. Drain β upgrade kubelet/kubectl β restart β uncordon (first CP)
5. Repeat steps 2-4 for additional control planes (use "kubeadm upgrade node")
6. Repeat steps 2-4 for each worker node
7. Verify all nodes and podsCommon Issues
βcouldnβt upgrade control planeβ β etcd not healthy
Restore etcd from backup, fix the issue, retry. Never force-upgrade past etcd errors.
Pods stuck Terminating during drain
Force delete: kubectl delete pod <name> --grace-period=0 --force. Or increase drain timeout: --timeout=300s.
API deprecation warnings after upgrade
Some API versions removed in new releases (e.g., extensions/v1beta1). Update manifests to current API versions before upgrading.
Worker node shows old version after upgrade
kubelet not restarted. Run: systemctl daemon-reload && systemctl restart kubelet.
Best Practices
- One minor version at a time β 1.28β1.29, never skip
- Backup etcd before every upgrade β your rollback safety net
- Drain nodes before upgrading kubelet β prevents workload disruption
- Upgrade control plane before workers β API server must be newest
- Read release notes β check for removed APIs and breaking changes
- Test in staging first β never upgrade production without validation
Key Takeaways
kubeadm upgrade applyon first control plane,kubeadm upgrade nodeon all others- Always: backup etcd β upgrade kubeadm β upgrade node β drain β upgrade kubelet β uncordon
- Only upgrade one minor version at a time
- Control plane nodes first, then workers
- CKA exam frequently tests this procedure β know the exact command order

Recommended
Kubernetes Recipes β The Complete Book100+ production-ready patterns with detailed explanations, best practices, and copy-paste YAML. Everything in one place.
Get the Book βLearn by Doing
CopyPasteLearn β Hands-on Cloud & DevOps CoursesMaster Kubernetes, Ansible, Terraform, and MLOps with interactive, copy-paste-run lessons. Start free.
Browse Courses βπ Deepen Your Skills β Hands-on Courses
Courses by CopyPasteLearn.com β Learn IT by Doing
