KubernetesLXXIV · kubeadmkubeadm
Upgrade plan — prepare, control-plane, workers in order
What you'll learn
- Plan a Kubernetes upgrade from start to finish
- Verify version skew policy and supported configurations
- Sequence control plane and worker upgrades
- Apply backup-before-change as the gate
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
A Kubernetes upgrade is a multi-step operation that affects every component: control plane, kubelet, CNI, add-ons. This lesson walks the planning, the version-slew policy, the backup-before-change gate, and the rollout order.
The upgrade plan
A Kubernetes upgrade is a structured operation:
flowchart LR
P[Plan] --> B[Backup etcd]
B --> V[Verify version skew]
V --> C1[Upgrade control plane 1]
C1 --> C2[Upgrade control plane 2]
C2 --> C3[Upgrade control plane 3]
C3 --> W1[Upgrade worker 1]
W1 --> W2[Upgrade worker 2]
W2 --> W3[Upgrade worker N]
W3 --> V2[Validate]
The control plane upgrades first; then workers. Within the control plane, follower first, leader last.
The version skew policy
Kubernetes officially supports:
- kube-apiserver + etcd: minor mismatch within 1 version.
- kubelet: up to 3 minor versions behind API server.
- kube-controller-manager, kube-scheduler, kube-proxy: up to 1 minor version ahead of or behind API server.
Examples (valid):
API server 1.34, kubelet 1.31-1.34 → ok
API server 1.34, kube-proxy 1.33-1.35 → ok
API server 1.34, etcd 3.6.x → ok
Examples (invalid):
API server 1.34, kubelet 1.30 → invalid (4 minor mismatch)
API server 1.34, etcd 3.4.x → invalid (version mismatch)
A simple upgrade (1.33 → 1.34) is well within skew. A jump (1.31 → 1.34) requires intermediate upgrades: 1.31 → 1.32 → 1.33 → 1.34.
The kubeadm upgrade plan
# Plan the upgrade
sudo kubeadm upgrade plan
[upgrade/config] Reading configuration from the cluster...
[upgrade/config] FYI: You can look at this config file with:
[upgrade/config] $ kubectl -n kube-system get cm kubeadm-config -o yaml
[preflight] Running preflight checks
[preflight] Pulling images required for this upgrade
[preflight] This might take a minute or two depending on the speed of your internet connection.
[preflight] Note: Some of the preflight checks may take a few seconds to complete.
[upgrade] Running cluster health checks
Upgrade to version 1.34.1 is available; applied to:
- kubeadm
- kubelet
- control plane
The plan shows:
- The Kubernetes version available.
- The components affected.
- The health checks (preflight).
sudo kubeadm upgrade apply v1.34.1
This is the actual upgrade on the control plane host.
The kubeadm upgrade apply sequence
On the first control-plane host (cp-1 / leader):
sudo kubeadm upgrade apply v1.34.1
The command:
- Verifies kubeadm and kubelet versions.
- Reads the kubeadm-config ConfigMap.
- Pulls new images.
- Updates the static pod manifests (API server, etc).
- Restarts the static pods (kubelet observes the manifest change).
- Updates the cluster’s Kubernetes version.
- Updates the kubelet binary via package manager.
After the command, cp-1 is at 1.34.1; cp-2 and cp-3 are still at 1.34.0. The cluster is in skew but functional.
$ sudo kubeadm upgrade plan...The follower control plane upgrade
On each additional control-plane host (follower first):
sudo kubeadm upgrade node
This:
- Upgrades the kubeadm binary.
- Upgrades the kubelet binary.
- Restarts the kubelet service.
The control plane static pods are already at the new
version (via the leader’s kubeadm upgrade apply); the
follower’s kubeadm upgrade node does not change those.
After: cp-1 = 1.34.1, cp-2 = 1.34.1, cp-3 still 1.34.0. The cluster has 2/3 of control plane at the new version.
The worker upgrade
Workers are upgraded with kubeadm upgrade node:
sudo kubeadm upgrade node
Before running:
# Substitute your own value before running:
WORKER=worker-03
# Drain the worker first
kubectl drain "$WORKER" --ignore-daemonsets --delete-emptydir-data
Then on the worker:
sudo kubeadm upgrade node
After:
# The worker drained above:
WORKER=worker-03
# Bring back
kubectl uncordon "$WORKER"
The worker is at 1.34.1; the cluster’s control plane is at 1.34.1; the rest is still at 1.34.0.
The CNI upgrade
The CNI plugin must be compatible with the new Kubernetes version. Check:
- Cilium: supports N-1 to N+1 minor versions.
- Calico: same.
- Flannel: same.
Upgrade the CNI separately, after the control plane upgrade:
# Cilium
helm upgrade cilium cilium/cilium --version 1.16.x ...
# Calico
kubectl apply -f calico-updated.yaml
Compatibility with the control plane’s API version is the key.
The add-on upgrades
Add-ons (CoreDNS, kube-proxy, ingress controllers) must be compatible:
# Check kube-proxy version
kubectl -n kube-system get ds kube-proxy -o jsonpath='{.spec.template.spec.containers[0].image}'
# Update kube-proxy via kubeadm
sudo kubeadm upgrade apply v1.34.1
# ... this updates the kube-proxy static manifest
CoreDNS upgrades separately:
helm upgrade coredns coredns/coredns --version x.y.z
The verification at each step
# After control plane upgrade
kubectl get nodes
# Expect: control plane nodes Ready, version reported as 1.34.1
kubectl get pods -n kube-system
# Expect: kube-apiserver, etcd, controller-manager, scheduler all Running
# After worker upgrade
kubectl get nodes -o wide
# Expect: worker at 1.34.1; older workers still at 1.34.0
# Final validation
kubectl api-resources
# Expect: API resources loaded without error
The rollback path
If the upgrade fails:
- Snapshot exists. Pre-upgrade snapshot was taken.
- Restore etcd from snapshot (Part LXIX).
- Restart cluster on the pre-upgrade version.
- Investigate. What broke; what needs to change before retrying.
A rollback is heavy; the goal is to avoid needing one. The snapshot is the safety net.
The upgrade plan template
UPGRADE PLAN: 1.34.0 → 1.34.1
================================
Team contacts:
- Lead: <name>
- Backup: <name>
- Vendor support: <info>
Window:
- Start: <timestamp>
- End: <timestamp>
Snapshot:
- Pre-upgrade: <timestamp>
- Post-upgrade: <timestamp>
Steps:
1. Take etcd snapshot
2. Verify snapshot integrity
3. Run sudo kubeadm upgrade plan (review outputs)
4. Run sudo kubeadm upgrade apply on cp-1 (leader)
5. Wait for cp-1 to be Ready at v1.34.1
6. Run sudo kubeadm upgrade node on cp-2, cp-3 (followers)
7. Verify each follower is at v1.34.1
8. Upgrade workers (sequentially, drain before upgrade)
9. Update CNI
10. Update add-ons (coredns, ingress, etc.)
11. Final validation
12. Take post-upgrade snapshot
13. Document
Rollback:
- Restore etcd from pre-upgrade snapshot
- Re-bootstrap on the prior version
Approvals:
- Change advisory board: <signed>
- Operations team: <signed>
The discipline
- Backup before every upgrade. The snapshot is the rollback path.
- Validate version skew. A multi-minor jump is a recipe for incidents.
- Plan every step. Written plans capture the order and the verification.
- Test on staging first. Production upgrades mirror staging.
- Verify at each step. kubectl / crictl / alert state confirms the change.
Quiz
Knowledge check · 4 questions
Q1. A kubelet can be how many minor versions behind the API server?
Q2. It is safe to skip minor Kubernetes versions (e.g., 1.32 → 1.34) if the kubeadm upgrade plan reports compatibility.
Q3. Walk the upgrade of a 3-control-plane + 5-worker cluster from 1.34.0 to 1.34.1.
Cluster: 3 stacked etcd, 5 workers. All at 1.34.0. The team plans to upgrade to 1.34.1.
Q4. Why is the leader upgraded last?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Backup before upgrade. Always.
- One minor at a time. Validate at each step.
- Followers first, leader last. Both in control plane and the API server upgrade.
- Update CNI and add-ons. They need version-specific configuration.
- Verify at each step. Don’t proceed if validation fails.
- Document the plan and the outcome. The plan is the runbook; the outcome is the post-mortem input.
The upgrade is a planned, ordered, validated sequence. Operating it well is following the plan.