Skip to main content
RunBook Academy

KubernetesLXXVII · Kubernetes UpgradesKubernetes upgrades

kubeadm upgrade apply — the leader's upgrade

Advanced⏱ ~15 minkubeadmkubectl

What you'll learn

  • Run kubeadm upgrade apply on the leader
  • Understand the phase-by-phase execution
  • Identify the static pod manifest updates
  • Verify the upgrade took effect

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 runs on the leader of the control plane. It performs the full upgrade of the cluster’s control plane components: API server, controller-manager, scheduler, etcd. This lesson walks the command, the phase-by-phase execution, and the verification.

The command

sudo kubeadm upgrade apply v1.34.1

The argument is the target Kubernetes version. The version must be a valid semver with the major, minor, and patch components. The command does not support multi-minor upgrades (e.g., v1.31.0 → v1.34.0) in a single call.

The phases

The command runs several phases:

flowchart LR
    A[Validate config] --> B[Pull images]
    B --> C[Update ControlPlane static pod manifests]
    C --> D[Update ClusterConfiguration]
    D --> E[Update kubelet config]
    E --> F[Update kubelet binary]
    F --> G[Update node labels/annotations]

Each phase has a defined output. If any phase fails, the command aborts and the cluster is in a partially-upgraded state.

Phase 1: Validate config

The command reads the cluster’s kubeadm config from the kubeadm-config ConfigMap in kube-system:

kubectl -n kube-system get cm kubeadm-config -o yaml

The config includes the current version, the ClusterConfiguration, the InitConfiguration, and the KubeletConfiguration. The validate phase verifies the config is consistent and the upgrade target is supported.

Phase 2: Pull images

The new images for the target version are pulled:

Pulling images required for this upgrade.
This might take a minute or two depending on the speed of your internet connection.

The images are:

  • registry.k8s.io/kube-apiserver:v1.34.1
  • registry.k8s.io/kube-controller-manager:v1.34.1
  • registry.k8s.io/kube-scheduler:v1.34.1
  • registry.k8s.io/kube-proxy:v1.34.1
  • registry.k8s.io/etcd:3.5.x
  • registry.k8s.io/pause:3.9
  • registry.k8s.io/coredns/coredns:v1.11.x

The pull is parallelized; the duration is bounded by the slowest image.

Phase 3: Update ControlPlane static pod manifests

The static pod manifests in /etc/kubernetes/manifests/ are updated:

ls /etc/kubernetes/manifests/
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
etcd.yaml

Each manifest’s image field is updated to the new version. The kubelet sees the manifest change via the hash; it terminates the existing pod and starts a new one with the new image.

sequenceDiagram
    participant K as kubeadm
    participant FS as /etc/kubernetes/manifests/
    participant KL as kubelet
    participant AS as API server pod
    K->>FS: write new kube-apiserver.yaml (v1.34.1)
    K->>KL: notify via file watch
    KL->>AS: terminate old pod
    KL->>AS: start new pod (v1.34.1)
    AS-->>K: pod started

The restart is brief (seconds). The LB routes around; clients see a 503 and retry.

Phase 4: Update ClusterConfiguration

The cluster’s ClusterConfiguration is updated to reflect the new version. The KubeadmConfig ConfigMap is updated:

apiVersion: v1
data:
  ClusterConfiguration: |
    apiServer:
      extraArgs:
        authorization-mode: Node,RBAC
      timeoutForControlPlane: 4m0s
    apiVersion: kubeadm.k8s.io/v1beta4
    certificatesDir: /etc/kubernetes/pki
    clusterName: kubernetes
    ...
kind: ConfigMap
metadata:
  name: kubeadm-config
  namespace: kube-system

The version is recorded in the ConfigMap.

Phase 5: Update kubelet config

The KubeletConfiguration is updated to match the new version’s defaults. The kubelet’s config file is rewritten at /var/lib/kubelet/config.yaml.

Phase 6: Update kubelet binary

The kubelet binary is updated via the package manager:

# Debian/Ubuntu
sudo apt-get update
sudo apt-get install -y kubelet=1.34.1-1.34

# RHEL/Fedora
sudo yum install -y kubelet-1.34.1-1.34

The kubelet service is restarted:

sudo systemctl restart kubelet

The kubelet starts with the new version.

Phase 7: Update node labels/annotations

The cluster’s node labels and annotations are updated:

metadata:
  annotations:
    kubeadm.kubernetes.io/cluster-id: 1a2b3c4d
    kubeadm.kubernetes.io/control-plane-endpoint: lb:6443
  labels:
    node-role.kubernetes.io/control-plane: ""
    node.kubernetes.io/exclude-from-external-load-balancers: ""

The version label is implicit (it is reported by the kubelet, not stored as a label).

The output

The full output of kubeadm upgrade apply:

[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/health] Checking API server health...
[upgrade/health] Checking controller-manager health...
[upgrade/health] Checking scheduler health...
[upgrade/health] Checking etcd health...

Upgrade to version 1.34.1 is available; applied to:
  - kubeadm
  - kubelet
  - control plane

[upgrade/apply] Applying the new version to the cluster

[upgrade/apply] Pulling images: ...
[upgrade/apply] Updating static pod manifests
[upgrade/apply] Updating KubeletConfiguration
[upgrade/apply] Updating kube-apiserver static pod
[upgrade/apply] Updating kube-controller-manager static pod
[upgrade/apply] Updating kube-scheduler static pod
[upgrade/apply] Updating etcd static pod
[upgrade/apply] Restarting kubelet

[upgrade/apply] Waiting for control plane to be ready
[upgrade/apply] Waiting for API server to be healthy
[upgrade/apply] Waiting for API server to be ready
[upgrade/apply] Updating configuration
[upgrade/apply] Updating cluster information

[upgrade] Successful upgrade to version 1.34.1

The command is silent on success; the final line is the success indicator.

The verification

# Cluster version
kubectl version
# Server Version: v1.34.1

# Node version
kubectl get nodes
# All control plane nodes Ready, version v1.34.1

# Static pod state
kubectl get pods -n kube-system
# kube-apiserver, controller-manager, scheduler, etcd all Running

# API server endpoint
kubectl get endpointslices -n default

The cluster is at the new version.

Cross-course references

  • The Linux course covers package manager-based binary upgrades.
  • The Observability course covers alerting during upgrade windows.
  • The Ansible course covers the equivalent of kubeadm upgrade apply for non-kubeadm clusters.

Quiz

Knowledge check · 4 questions

  1. Q1. What argument does `kubeadm upgrade apply` take?

  2. Q2. `kubeadm upgrade apply v1.34.1` will upgrade a cluster from 1.30 to 1.34 in a single call.

  3. Q3. Walk the leader's upgrade step by step.

    Leader control plane host cp-1. The cluster is at 1.34.0. The team is upgrading to 1.34.1. The snapshot is verified. The release notes are read.

  4. Q4. How is the static pod restart triggered by `kubeadm upgrade apply`?

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

Production discipline

  • Run from the leader. The leader’s upgrade is the cluster’s upgrade.
  • Snapshot before. The pre-upgrade snapshot is the rollback path.
  • Watch the static pod restart. The brief unavailability is bounded by the LB.
  • Verify at each phase. The output walks the phases; review each line.
  • Don’t proceed on partial upgrade. If a phase fails, investigate before retrying.
  • Document the upgrade. Step-by-step notes in the runbook.

The leader’s upgrade is the most disruptive step in the Kubernetes upgrade sequence. Operating it well is understanding the phases and the static pod restart.