Cloud & Infrastructure
Kubernetes v1.37: upgrading without downtime
Static pods break, old cAdvisor flags stop the kubelet, SELinuxMount is now on. What actually goes wrong upgrading to Kubernetes v1.37.
Kubernetes v1.37 was released on 26 August 2026. Three changes break running clusters on upgrade: static pods may no longer reference secrets or config maps, the kubelet refuses to start when deprecated cAdvisor flags are set, and SELinuxMount is now on by default. The frequently quoted containerd 1.x deadline, by contrast, has been postponed again.
The full release notes are in CHANGELOG-1.37.md in the kubernetes/kubernetes repository, and the feature overview in the sneak peek of 31 July 2026. Anyone running between two and twenty production clusters needs only the part that hurts: an order of operations and a handful of check commands. That is what follows.
Static pods may no longer reference secrets and config maps
Kubernetes v1.37 removes the PreventStaticPodAPIReferences feature gate. Static pods using configMapRef or secretRef will not start after the upgrade. The ones affected are mostly bare-metal installations and self-managed control planes, not the standard components kubeadm manages.
This is a bug fix, not an imposition. Static pods are read by the kubelet directly out of /etc/kubernetes/manifests/ and do not go through the API server. That they could nonetheless reference API objects was a defect. According to the release entry the gate has been removed and can no longer be disabled.
The check takes a minute per node:
# On every control plane and worker node
grep -rlE 'configMapRef|secretRef' /etc/kubernetes/manifests/
Every output line is a manifest you have to rework before the upgrade. The replacement is unspectacular: write the values as literals into the pod spec, mount files through hostPath, or move the component out of the static pod directory into a real DaemonSet.
The kubelet will not start when old cAdvisor flags are set
The kubelet in v1.37 refuses to start as soon as a deprecated cAdvisor option appears in its configuration. The embedded cAdvisor now uses the leaner module github.com/google/cadvisor/lib, and of the old flags only --housekeeping-interval survives.
The release notes carry this as a deprecation, but in practice it behaves like a hard breaking change: a node with --containerd, --boot-id-file, --machine-id-file, --container-hints, --global-housekeeping-interval, --event-storage-age-limit, or one of the --storage-driver-* flags simply does not come back after a restart.
Where you look matters. The systemd unit is only one of the places: kubeadm puts its flags in /var/lib/kubelet/kubeadm-flags.env, and many distributions additionally in /etc/default/kubelet. Checking only systemctl cat gives you a clean result on an affected node.
# On every node: find forbidden cAdvisor flags in all three sources
FLAGS='--(application-metrics-count-limit|boot-id-file|container-hints|containerd|enable-load-reader|event-storage-|global-housekeeping-interval|log-cadvisor-usage|machine-id-file|storage-driver-)'
systemctl cat kubelet 2>/dev/null | grep -E -- "$FLAGS"
grep -hE -- "$FLAGS" /var/lib/kubelet/kubeadm-flags.env /etc/default/kubelet 2>/dev/null
No output means clean. On top of that, the metrics container_cpu_load_average_10s, container_cpu_load_d_average_10s and container_tasks_state disappear from /metrics/cadvisor. Anyone with a Grafana panel or an alerting rule hanging off those sees a silent gap after the upgrade rather than an error. That is the more unpleasant variant. More on this in our article on observability you actually read.
containerd 2.0 under Kubernetes: is the move mandatory for v1.37?
No, containerd 2.0 is not mandatory with Kubernetes v1.37 either. The claim has been circulating in upgrade guides since the v1.36 cycle and is wrong. Removal of the deprecated kubelet configuration flags along with the CRI fallback has been postponed twice: in CHANGELOG-1.36.md from v1.36 to v1.37, and in CHANGELOG-1.37.md again from v1.37 to v1.38 (PR #139121, merged 22 May 2026), explicitly “to align with containerd v1.7 support”.
Do not relax on that account. According to containerd RELEASES.md, extended support for containerd 1.7 ends in September 2026, and it is explicitly limited to Kubernetes 1.30 through 1.32 on GKE. For anything else, 1.7 is already unmaintained.
The kubelet tells you itself when the music stops:
# Node inventory: kubelet version, runtime, OS image
kubectl get nodes -o custom-columns='NODE:.metadata.name,\
KUBELET:.status.nodeInfo.kubeletVersion,\
RUNTIME:.status.nodeInfo.containerRuntimeVersion,\
OS:.status.nodeInfo.osImage'
# kubelet metrics: cgroup version and the runtime's end of support
kubectl get --raw "/api/v1/nodes/<NODE>/proxy/metrics" \
| grep -E '^kubelet_(cgroup_version|cri_losing_support)'
kubelet_cri_losing_support is a gauge with a version label reporting the Kubernetes version in which the currently running CRI implementation loses support. Alpha stability, but exactly the number you need when planning.
What the jump from 1.7 to 2.x actually means:
| Point | containerd 1.7 | containerd 2.x |
|---|---|---|
| Support | extended to September 2026, only for K8s 1.30–1.32 on GKE | 2.3 as LTS until 30 April 2028 |
| CRI API | v1 and v1alpha2 | v1 only, v1alpha2 removed |
config.toml | version 2 | version 3 recommended, version 2 still works |
| Docker schema 1 images | pull possible, deprecated | disabled in 2.0, removed in 2.1 |
Runtime plugins as *.so | supported | removed in 2.1, use external plugins |
If you migrate, go to containerd 2.3: LTS until 30 April 2028. containerd 2.2 already goes out of support on 6 November 2026, and 2.1 has been EOL since 3 July 2026. The config does not have to move at the same time; containerd 2.x still reads version 2.
If you are not sure whether your nodes come back after the kubelet restart, you can find out in about an hour: node inventory, kubelet unit diff, static pod scan. If you would rather not work through it yourself, we will look at it together.
cgroup v1 was settled in v1.35, not now
The kubelet has refused to start on cgroup v1 nodes since Kubernetes v1.35, because failCgroupV1 defaults to true there. The v1.37 sneak peek lists it as an ongoing change, not a new one.
In practice: anyone still on v1.34 does not meet cgroup v1 at the jump to v1.37 but at the intermediate step to v1.35. Affected are older node images and on-premise estates, typically CentOS 7, RHEL 7 and Ubuntu 18.04. The kubelet_cgroup_version metric from the block above answers this per node without anyone having to log in.
kube-proxy IPVS: the clock is running, but slowly
kube-proxy’s IPVS mode disappears over four releases, not in this one. KEP-5495 lays out the path: v1.35 warnings, v1.37 a new KubeProxyIPVS feature gate (on by default), v1.40 gate off by default, v1.43 code removed, v1.46 gate removed.
The reasoning is honest and readable in the KEP: “sig-network currently lacks maintainers who are familiar with the ipvs backend code.” On top of that, IPVS still uses iptables underneath. The migration target is nftables, GA since v1.33.
kubectl -n kube-system get configmap kube-proxy \
-o jsonpath='{.data.config\.conf}' | grep 'mode:'
An empty mode: is worth a warning from v1.37 as well: kube-proxy now reports when no mode is set explicitly, because the Linux default will move from iptables to nftables. Set the value explicitly, even if you want to keep current behaviour.
Which Kubernetes version still has support
Kubernetes maintains the three most recent minor releases. The documentation calls that “roughly a year”; the last three releases actually ran 14.0, 14.4 and 14.2 months. Plan for twelve months and be pleased about the rest. As of kubernetes.io/releases on 18 August 2026:
| Version | Release | End of life | What to do |
|---|---|---|---|
| v1.34 | 27.08.2025 | 27.10.2026 | Urgent. Two months left, three minor jumps to v1.37 |
| v1.35 | 17.12.2025 | 28.02.2027 | cgroup v1 already enforced, IPVS warnings active |
| v1.36 | 22.04.2026 | 28.06.2027 | The most comfortable position, one jump to v1.37 |
| v1.37 | 26.08.2026 | approx. October 2027 * | New, initially at .0 patch level |
* EOL for v1.37 has not been published. The value is extrapolated from the 14-month pattern of the three predecessors and should be treated as a planning figure rather than a commitment.
For Swiss teams on Exoscale SKS there is a second cadence: minor versions are supported for around 14 months, upgrades must run sequentially through every minor version, and the control plane is raised first, after which the node pools are cycled. From v1.34 to v1.37 that is three rounds, not one.
The upgrade order we recommend
An upgrade without downtime follows the official version skew policy: control plane before nodes, no skipped minor versions on the kube-apiserver.
- Check before touching anything. Static pod scan, cAdvisor flag scan,
kubelet_cgroup_version,kubelet_cri_losing_support, kube-proxy mode. All five commands are above. - Clear
scheduling.k8s.io/v1alpha2out of etcd. v1.37 removes the version entirely. The core typesWorkloadandPodGrouphave been promoted toscheduling.k8s.io/v1beta1, the rest tov1alpha3. Existing objects must go before the update. - Raise the kube-apiserver, then kube-controller-manager, kube-scheduler and cloud-controller-manager. Those three may be at most one minor version older than the API server.
- Lift one worker node as a test. kubelet and kube-proxy may be up to three minor versions older than the kube-apiserver. So you have time, and you need it: the first node is the experiment.
- Roll the remaining node pools, with PodDisruptionBudgets that deserve the name. A PDB with
minAvailable: 1on two replicas does not block a drain, it only delays it.
One point that often gets lost: SELinuxMount is GA in v1.37 and on by default. On clusters with SELinux enabled — practically every RHEL and OpenShift estate — that can break running workloads. Kubernetes published a dedicated blog post on 22 April 2026 that makes the affected patterns identifiable in a v1.36 cluster. Without SELinux, nothing changes.
When you should not upgrade
Do not upgrade to v1.37.0. Wait for v1.37.1 or v1.37.2, unless you have a concrete reason. On release day a .0 is the least production-exercised state of a version, and the history of the urgent upgrade notes gives little cause for optimism.
The trade-off is real and cuts both ways: waiting accumulates distance from v1.34, whose support ends on 27 October 2026. Because kube-apiserver may not skip minor versions, that is three sequential upgrades. Starting only in October means three jumps under time pressure rather than one at leisure. Every jump is operational effort, and operational effort is the largest item when you work through what Kubernetes really costs in Switzerland.
Our line: anyone on v1.36 has peace until June 2027 and can wait for .2. Anyone on v1.34 starts this week, and starts with v1.35, not v1.37. And anyone in the middle of a quarterly close or running a release freeze postpones the whole thing deliberately and in writing, rather than forgetting it.
Also, do not put everything into the same maintenance window. Ingress NGINX was retired in March 2026 with no further security patches, backed according to internal Datadog research by around half of all cloud-native environments. Moving to the Gateway API is its own project with its own risk, not a sideshow of a minor upgrade.
A cluster is not an end in itself anyway. Before planning three upgrade rounds, it is worth asking whether a cluster is the right answer at all.
Frequently asked
How does a Kubernetes cluster upgrade without downtime work?
A downtime-free upgrade raises the control plane first, then the nodes. kube-apiserver goes first, then controller-manager and scheduler, and finally kubelet and kube-proxy. Workloads stay available when every application has at least two replicas, a sensible PodDisruptionBudget and working readiness probes. Nodes are drained one at a time, not in parallel.
Which Kubernetes version is still supported?
Supported are v1.35, v1.36 and v1.37 once v1.37 is out. v1.34 reaches end of life on 27 October 2026. Kubernetes maintains the three most recent minor releases as a rule, which works out to roughly a year of patch support per version. Managed providers differ: Exoscale SKS gives around 14 months.
How do I check which kube-proxy mode my cluster uses?
The command kubectl -n kube-system get configmap kube-proxy -o jsonpath='{.data.config\.conf}' | grep 'mode:' reads the mode out of the ConfigMap. An empty value means the default, currently iptables on Linux. If it says ipvs, plan the migration to nftables: from v1.40 IPVS is off by default, and from v1.43 it is removed.
Do I have to move to containerd 2.x for Kubernetes v1.37?
No, not necessarily. Removal of the kubelet CRI fallback has been postponed to v1.38. Extended support for containerd 1.7 does however end in September 2026 and covers only Kubernetes 1.30 through 1.32 on GKE. In practice: plan the move to containerd 2.3 now, but not in the same maintenance window as the v1.37 upgrade.
A little over two months until v1.34 reaches end of life. To v1.37 that is three sequential jumps, and each needs its own maintenance window. We will walk the path with you once: which version first, what breaks at each jump, how long it realistically takes. At the end you have an order of operations, not a presentation.
Write to us through contact with the version you are running and how many clusters hang off it, and we will prepare the path. Or book a slot directly. What else we build and operate in clusters is under Kubernetes and infrastructure.