Skip to main content
RunBook Academy

KubernetesLXXIV · kubeadmkubeadm

kubeadm upgrade apply — phases, validation, post-upgrade checks

Advanced⏱ ~18 minkubeadmkubectl

What you'll learn

  • Run kubeadm upgrade apply with the right flags
  • Walk the per-host phases and what they produce
  • Verify the cluster after each upgrade step
  • Apply the production discipline of upgrade validation

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

Not yet marked complete on this device.

kubeadm upgrade apply is the command that takes a control-plane host from one Kubernetes version to the next. The command is multi-phase and order-sensitive. This lesson walks the phases, the validation, and the production discipline of running upgrades.

The command

On the leader (or the first control plane host):

sudo kubeadm upgrade apply v1.34.1

The version argument is a specific patch version. The command:

  1. Pre-flight checks.
  2. Pulls new images.
  3. Updates the cluster-info map.
  4. Writes new static pod manifests.
  5. Restarts the static pods (kubelet observes the manifest change).
  6. Updates the kubelet configuration.
  7. Updates the cluster’s Kubernetes version.
sequenceDiagram
    autonumber
    participant Op as Operator
    participant KU as kubeadmUpgrade
    participant I as ImageRegistry
    participant K as kubelet
    participant CM as kubeadmConfig
    Op->>KU: kubeadm upgrade apply v1.34.1
    KU->>KU: preflight checks
    KU->>I: pull new control plane images
    KU->>CM: update ClusterConfiguration
    KU->>K: write new static pod manifests
    K->>K: observe manifest change
    KU->>K: update kubelet configuration
    K-->>Op: upgrade complete

Each phase is observable in the command’s output.

The preflight checks

[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.
[preflight] Note: Some recommended components (CNI, kube-proxy, CoreDNS) have not been upgraded.
        Please double-check the upgrade plan documentation.
[upgrade] Running cluster health checks

The preflight checks:

  • The cluster is healthy (components Running).
  • kubeadm has the right images.
  • The kubelet can be upgraded.

A failing preflight stops the upgrade.

The pull-images phase

[upgrade/etcd] Pulling image: registry.k8s.io/etcd:3.6.5-0
[upgrade/etcd] Pulled image: etcd 3.6.5-0
[upgrade/apiserver] Pulling image: registry.k8s.io/kube-apiserver:v1.34.1
[upgrade/apiserver] Pulled image: kube-apiserver v1.34.1
[upgrade/controller-manager] Pulling image: ...
[upgrade/scheduler] Pulling image: ...

The images are pulled via containerd. The kubelet will use them when the manifests are updated.

The static pod updates

[upgrade/apiserver] Updated static pod manifest for kube-apiserver
[upgrade/controller-manager] Updated static pod manifest for kube-controller-manager
[upgrade/scheduler] Updated static pod manifest for kube-scheduler
[upgrade/etch] Updated static pod manifest for etcd

The static pod manifests at /etc/kubernetes/manifests/ are rewritten. The kubelet observes the change and restarts the pods.

The kubelet reconfiguration

[upgrade/kubelet] Upgrading kubelet configuration...
[upgrade/kubelet] Restarting kubelet...

The kubelet’s --config flag points at /var/lib/kubelet/config.yaml, which is regenerated. The kubelet is restarted.

Read-only / Safe
$ kubectl -n kube-system get cm kubeadm-config -o jsonpath='{.data.ClusterConfiguration}' | grep kubernetesVersion
kubernetesVersion: v1.34.1

The follow-up command

On each follower:

sudo kubeadm upgrade node

The follower’s command:

  1. Verifies the kubelet version.
  2. Restarts kubelet.
  3. Upgrades the local kubeadm.

The follower’s static pods are already updated; only the kubelet needs restart.

[upgrade] Upgrading kubelet...
[upgrade] Restarting kubelet after upgrade...

The follower is now at v1.34.1.

The worker upgrade

On each worker:

# Substitute your own value before running:
WORKER=worker-01

# 1. Drain the worker
kubectl drain "$WORKER" --ignore-daemonsets --delete-emptydir-data

# 2. Upgrade on the worker
sudo kubeadm upgrade node

# 3. Bring the worker back
kubectl uncordon "$WORKER"

The drain moves Pods off the worker; the upgrade + restart the kubelet; uncordon re-enables scheduling.

The image pulling options

sudo kubeadm upgrade apply v1.34.1 \
  --image-pull-timeout=15m \
  --etcd-upgrade=true \
  --certificate-renewal=true

Flags:

FlagPurpose
--image-pull-timeoutTime to pull images before timing out
--etcd-upgradeAllow etcd to be upgraded to a newer minor
--certificate-renewalAuto-renew cluster certificates during upgrade

The post-upgrade validation

# 1. The cluster's version is updated
kubectl version

# 2. The control plane nodes reflect the upgrade
kubectl get nodes
# Version column: v1.34.1

# 3. The components are healthy
kubectl get pods -n kube-system
# All Running

# 4. API responses are clean
kubectl get ns
kubectl get nodes -o wide
kubectl api-resources

# 5. Endpoints are populated
kubectl get endpointslices -A | head

The validation checklist

POST-UPGRADE VALIDATION
=======================

Date: 2026-08-16
Operator: <name>
Cluster: production
Upgrade: 1.34.0 → 1.34.1

Pre-upgrade: kubectl get nodes -o wide > /tmp/before.txt
[ ] All nodes Ready
[ ] All control plane pods Running
[ ] API requests succeed
[ ] API resources load without error
[ ] Endpoints populated for key services
[ ] Workloads continue running (deployments, statefulsets, etc.)
[ ] Network policies enforced
[ ] DNS resolves
[ ] Smoke test passes

Post-upgrade snapshot: /backup/etcd-snapshot-post-20260816-1230.db

The rollback procedure

If the upgrade fails or breaks the cluster:

flowchart LR
    A[Upgrade broke cluster] --> B[Restore from pre-upgrade snapshot]
    B --> C[Re-init on prior version]
    C --> D[Re-validate]

The restore is identical to the procedure in Part LXIX. The pre-upgrade snapshot is the rollback path.

The sub-phases of upgrade

sudo kubeadm upgrade apply v1.34.1 --dry-run

A dry-run shows what would happen without changing the cluster.

sudo kubeadm upgrade apply v1.34.1 -f
# -f forces the upgrade

A force option overrides some preflight checks (use carefully).

The image sources

The images are pulled from registry.k8s.io by default. For airgapped clusters:

sudo kubeadm upgrade apply v1.34.1 \
  --kubernetes-version=v1.34.1 \
  --image-repository=registry.internal.example/kubernetes

The image repository points to the cluster’s private registry.

The post-upgrade cleanup

# 1. Verify the cluster
kubectl cluster-info
# Kubernetes control plane is running at https://api.example:6443

# 2. Check the kubelet logs
sudo journalctl -u kubelet --since "30 minutes ago"
# Look for: started kubelet v1.34.1, no errors

# 3. Check the static pods
sudo crictl pods | grep -E 'etcd|apiserver|scheduler|controller'

# 4. Final: take a post-upgrade snapshot
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
  --cacert=... --cert=... --key=... \
  snapshot save /backup/etcd-snapshot-post-upgrade.db

The post-upgrade snapshot is the new “known-good” state.

The CNI upgrade

After Kubernetes is upgraded, upgrade the CNI to a compatible version:

# Cilium example
helm upgrade cilium cilium/cilium --version 1.16.x \
  -n kube-system \
  --set kubeProxyReplacement=true

The CNI’s release notes specify the supported Kubernetes versions.

Quiz

Knowledge check · 4 questions

  1. Q1. Which kubeadm upgrade subcommand runs on the leader control-plane host?

  2. Q2. kubeadm upgrade can update etcd implicitly without explicit opt-in.

  3. Q3. The control plane upgrade partially completes: API server is on the new version; etcd upgrade was skipped (no flag). Walk the remediation.

    The team runs `kubeadm upgrade apply v1.34.1` on the leader; the command reports success for API server, controller-manager, scheduler; etcd was not upgraded. The team did not pass --etcd-upgrade=true, so etcd is still at 3.5.x but the API server expects 3.5.x-1.

  4. Q4. Why is `kubeadm upgrade apply` only valid on the leader / first control-plane host? What happens if run on a follower?

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Backup before upgrade. Always.
  • Validate at each step. Each phase has a verifiable outcome.
  • Apply on the leader, upgrade node on followers. The sequence matters.
  • Post-upgrade snapshot. The new “known-good” anchor.
  • CNI + add-ons after. They need version-specific configs.
  • Document every step. The plan + outcome feed the runbook.

kubeadm upgrade apply is the cluster’s controlled disruption. Operating it well is the foundation of every future cluster operation.