KubernetesLXXVIII · Version SkewVersion skew
Version skew policy — the compatibility matrix
What you'll learn
- State the version skew policy for each component
- Apply the policy to a 1.34.x cluster
- Identify valid and invalid skew combinations
- Plan multi-minor upgrades around the skew policy
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
The version skew policy is the official Kubernetes compatibility matrix. It defines which combinations of component versions are supported. This lesson walks the policy, applies it to a 1.34.x cluster, and identifies valid and invalid combinations.
The components
A Kubernetes cluster has these versioned components:
| Component | Where it runs | Versioning |
|---|---|---|
| kube-apiserver | Control plane | Tracks Kubernetes minor |
| kube-controller-manager | Control plane | Tracks Kubernetes minor |
| kube-scheduler | Control plane | Tracks Kubernetes minor |
| cloud-controller-manager | Control plane | Tracks Kubernetes minor |
| kube-proxy | Worker | Tracks Kubernetes minor |
| kubelet | Worker | Tracks Kubernetes minor |
| kubectl | Operator workstation | Tracks Kubernetes minor |
| etcd | Control plane (or external) | etcd’s own versioning |
Everything above etcd is a Kubernetes component; etcd is a separate project with its own release train.
flowchart LR
A["kube-apiserver<br/>the newest component"]
A -->|up to 1 minor older| B[kube-controller-manager]
A -->|up to 1 minor older| C[kube-scheduler]
A -->|up to 1 minor older| D[cloud-controller-manager]
A -->|up to 3 minor older| E[kube-proxy]
A -->|up to 3 minor older| F[kubelet]
G["kubectl<br/>1 minor either side"] --> A
A --> H[etcd]
The skew policy
The official policy (kubernetes.io/releases/version-skew-policy):
| Component | Allowed skew relative to kube-apiserver |
|---|---|
| kube-apiserver | The reference. In an HA control plane the oldest and newest instances stay within 1 minor of each other |
| kube-controller-manager, kube-scheduler, cloud-controller-manager | Up to 1 minor older; never newer |
| kubelet | Up to 3 minor older; never newer |
| kube-proxy | Up to 3 minor older; never newer (and within 3 minor of the kubelet it runs alongside) |
| kubectl | Within 1 minor either side |
| etcd | Not governed by this policy; kubeadm pins one etcd version per K8s minor (3.6.x for 1.34.x) |
The policy is one-directional. The kube-apiserver is the newest Kubernetes component in the cluster: every other component may lag it, and none of them may run ahead of it. The window differs — 1 minor for the controller managers and the scheduler, 3 minors for the kubelet and kube-proxy — but the direction does not. kubectl is the single exception, because it is a client rather than a cluster component, and is supported 1 minor on either side.
Applying to 1.34.x
For a cluster at 1.34.x:
- kube-apiserver: 1.34.x
- kube-controller-manager, kube-scheduler, cloud-controller-manager: 1.33.x or 1.34.x
- kubelet: 1.31.x, 1.32.x, 1.33.x, or 1.34.x
- kube-proxy: 1.31.x, 1.32.x, 1.33.x, or 1.34.x
- kubectl: 1.33.x, 1.34.x, or 1.35.x
- etcd: 3.6.x — the version kubeadm 1.34 ships
The valid combinations are bounded by the policy.
| Component | Min version | Max version |
|---|---|---|
| kube-apiserver | 1.34.0 | 1.34.x |
| kube-controller-manager | 1.33.0 | 1.34.x |
| kube-scheduler | 1.33.0 | 1.34.x |
| cloud-controller-manager | 1.33.0 | 1.34.x |
| kube-proxy | 1.31.0 | 1.34.x |
| kubelet | 1.31.0 | 1.34.x |
| kubectl | 1.33.0 | 1.35.x |
| etcd | 3.6.0 | 3.6.x |
kubectl is the only row whose maximum is above 1.34.x.
Valid combinations
Valid for 1.34.x apiserver:
apiserver: 1.34.0
kubelet: 1.31.0, 1.32.0, 1.33.0, 1.34.0 → all OK
kube-proxy: 1.31.0, 1.32.0, 1.33.0, 1.34.0 → all OK
scheduler: 1.33.0, 1.34.0 → both OK
kubectl: 1.33.0, 1.34.0, 1.35.0 → all OK
etcd: 3.6.x → OK
Invalid combinations
Invalid for 1.34.x apiserver:
apiserver: 1.34.0
kubelet: 1.30.0 → INVALID (4 minor behind)
kubelet: 1.35.0 → INVALID (newer than the apiserver)
kube-proxy: 1.35.0 → INVALID (newer than the apiserver)
scheduler: 1.32.0 → INVALID (2 minor behind)
scheduler: 1.35.0 → INVALID (newer than the apiserver)
kubectl: 1.32.0 → INVALID (2 minor behind)
etcd: 3.4.x → INVALID (1+ minor mismatch)
A combination that violates the skew policy is not supported. The cluster may continue to run, but the behavior is undefined.
The skew during a rolling upgrade
A typical rolling upgrade:
gantt
title Rolling upgrade skew
dateFormat YYYY-MM-DD
section Apiserver
v1.33.0 :done, 2026-08-10, 1d
v1.34.0 :active, 2026-08-11, 7d
section Kubelet
Some v1.32.0 :done, 2026-08-10, 1d
Some v1.33.0 :active, 2026-08-11, 7d
All v1.34.0 :crit, 2026-08-15, 5d
During the upgrade, the apiserver is at 1.34.0, but some kubelets are still at 1.32.0 or 1.33.0. The skew is within policy (1.32.0 is 2 minor behind, OK). The cluster is functioning.
The skew during a multi-minor upgrade
A multi-minor upgrade (1.31 → 1.34) is not supported in a single call. The intermediate steps are required:
1.31 → 1.32 → 1.33 → 1.34
Each step is a separate upgrade. The cluster is at 1.31, then 1.32, then 1.33, then 1.34. The skew policy is maintained at each step.
The skew and kubectl
kubectl is the operator’s client, and the only piece of the picture supported 1 minor either side of the apiserver. A kubectl one minor behind cannot drive resources or subcommands the newer apiserver added; a kubectl one minor ahead may send fields the older apiserver silently drops. Neither is an error condition, but both are a reason to keep the workstation in step with the cluster.
kubectl version
--short was removed in Kubernetes 1.28; plain kubectl version has
printed the short form by default ever since, and passing --short
now fails with unknown flag: --short. The output is three lines —
Client Version, Kustomize Version (the kustomize build embedded in
this kubectl, which tracks the kubectl release rather than the
cluster), and Server Version. The first and the last are the two to
compare; when they agree, the client and server versions are aligned.
Use kubectl version -o json when you want to read the versions from
a script rather than by eye.
Cross-course references
- The Linux course covers binary compatibility concepts.
- The Terraform course covers Kubernetes provider version pinning.
- The Ansible course covers module version pinning.
Quiz
Knowledge check · 4 questions
Q1. How many minor versions can a kubelet be behind the kube-apiserver?
Q2. kubeadm supports upgrading a cluster from 1.31 to 1.34 in a single call.
Q3. Validate the version skew of a 3-control-plane + 5-worker cluster.
Cluster: apiserver 1.34.0; kubelets on 3 workers at 1.32.0 (older wave), 2 workers at 1.34.0 (newer wave); kube-proxy 1.34.0; kubectl on operator workstation 1.35.0; etcd 3.6.x.
Q4. Summarize the skew policy for kube-controller-manager, kube-scheduler, and cloud-controller-manager.
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Track the version of every component. kubeadm upgrade plan reports the current and target versions.
- Stay within the skew policy. Components outside the policy are unsupported.
- Plan multi-minor upgrades as a sequence. Each intermediate step is a separate upgrade.
- Update kubectl alongside the cluster. Version drift is a common operational issue.
- Document the skew in the runbook. The component versions, the policy boundary, the upgrade plan.
- Validate the skew before every operation. A pre-flight check before an upgrade.
The skew policy is the cluster’s compatibility contract. Operating it well is staying within the policy and planning upgrades around it.