Kubernetes 1.37 removes 18 deprecated cAdvisor flags from kubelet, and this isn't the kind of deprecation you can put off for a quarter. If a removed flag is still set anywhere in a node's kubelet configuration, kubelet refuses to start. Not a warning buried in a log, not a metric that quietly stops reporting: the node doesn't come back. The fix itself is small once you find the flag, but on a real fleet those flags hide in more places than the release notes mention, kubelet's own config, kubeadm's cluster config, systemd drop-ins, and the launch templates that boot managed node groups on EKS, GKE, and AKS. Audit all four before you touch the version number.
What changed: kubelet's cAdvisor lost three legacy surfaces
Kubelet's embedded cAdvisor now runs on the leaner github.com/google/cadvisor/lib module instead of the older monitoring stack it carried for years, according to the change that swapped kubelet's cAdvisor for its trimmed-down library. That swap takes three things out with it. First, the 18 deprecated flags covered below. Second, cAdvisor's application and custom metrics: the userDefinedMetrics field in /stats/summary, and the container_application_* metric families in /metrics/cadvisor. Third, three specific series from /metrics/cadvisor itself: container_cpu_load_average_10s, container_cpu_load_d_average_10s, and container_tasks_state.
The second and third group won't stop a node. If a dashboard or alert queries any of those metric names, it goes quiet the moment the node upgrades to 1.37, no error, just a series that stops reporting. The flags are the part that stops kubelet cold, which is why they get the rest of this article.
The 18 removed cAdvisor flags
Kubernetes 1.37 removes these flags outright. If kubelet finds any of them still set, whether on the command line or inside a KubeletConfiguration file, it fails to start:
--application-metrics-count-limit--boot-id-file--container-hints--containerd--containerd-namespace--enable-load-reader--event-storage-age-limit--event-storage-event-limit--global-housekeeping-interval--log-cadvisor-usage--machine-id-file--storage-driver-user--storage-driver-password--storage-driver-host--storage-driver-db--storage-driver-table--storage-driver-secure--storage-driver-buffer-duration
That's 18. Only one flag from the old cAdvisor surface survives: --housekeeping-interval, easy to mistake for --global-housekeeping-interval above, which is one of the 18 gone. Everything else on that list isn't deprecated-and-ignored anymore. It's gone in a way that stops the kubelet process from starting at all.
Where these flags actually hide
Kubernetes' own changelog gives this the one line every deprecation gets: remove these from your kubelet configuration. That's accurate and not very useful, because "your kubelet configuration" isn't one file on a real fleet. It's at least four different places, and an audit that checks only one of them will pass clean and still take a node down on upgrade day.
Start with kubelet itself. Check both the systemd unit's ExecStart command line and whatever KubeletConfiguration YAML file it loads at boot, since a flag can be set in either spot and only one of them turns up in a quick ps aux grep.
If the cluster is kubeadm-managed, the flags can also sit in ClusterConfiguration, under nodeRegistration.kubeletExtraArgs. That config gets copied onto every new node at join time, so a stale flag there reproduces itself onto every node you add until someone catches it.
Systemd drop-ins are the third hiding place: files under /etc/systemd/system/kubelet.service.d/*.conf that override or extend the base unit. Ops teams reach for drop-ins precisely to set node-specific args without editing the main unit, which is exactly the kind of file that gets copy-pasted across a node pool and then forgotten.
The fourth place is the one upstream docs skip entirely, because it's cloud-specific: managed-node-group bootstrap. On EKS, that's bootstrap.sh arguments or user data baked into the launch template. On GKE, it's node pool metadata. On AKS, it's the custom node configuration set at pool creation. If a node group was stood up two or three years ago and nobody's touched the bootstrap script since, that's the most likely spot a deprecated flag is still sitting.
How to audit your nodes before upgrading to Kubernetes 1.37
1. Grep every node's live kubelet args and config for the 18 flag names
Run ps aux | grep kubelet alongside the config file kubelet actually loads, on every node, not a sample. Match the flag names verbatim rather than just the --storage-driver or --event-storage prefix, since partial matches will miss flags that share a prefix but aren't on the removed list.
2. Check kubeadm's ClusterConfiguration and KubeletConfiguration
Pull the cluster config kubeadm stores in kube-system and check nodeRegistration.kubeletExtraArgs there, then check the same field in the join config used for each node pool. A flag set once in the cluster config propagates to every node that joins after it.
3. Check systemd drop-ins on every node pool, not just the control plane
Teams audit the control plane and stop, but worker pools accumulate their own drop-ins over time, especially in clusters where different pools were provisioned by different scripts or different engineers at different points.
4. Check managed-node-group launch templates and bootstrap scripts
Pull the current launch template version or bootstrap script actually attached to each node group, not just the copy sitting in your infrastructure-as-code repo. A manual console edit drifts from what's checked in more often than teams expect, and this is cloud-provider territory upstream Kubernetes docs don't touch.
5. Strip the flags and roll the upgrade through one node pool first
Remove the flags, then upgrade a single pool and confirm every node joins and stays Ready before touching the rest of the fleet. A flag missed on one pool tells you before it tells you on all of them.
6. Confirm metrics.k8s.io consumers still resolve after the v1 promotion
HPA and kubectl top both read from metrics.k8s.io. The move from v1beta1 to v1 is compatible, but check for anything that pins the old API version by name, an older Helm chart or a hardcoded API path, and update it to the new one.
Other Kubernetes 1.37 changes platform teams should track
metrics.k8s.io graduates from v1beta1 to v1, unchanged, according to the official Kubernetes 1.37 release announcement. That's the good-news item in this release. Nothing to migrate, no flag to strip, just a stable API sitting where a beta one used to be.
kubeadm drops its v1beta3 API entirely, after carrying a deprecation warning since Kubernetes 1.31, per the change that dropped kubeadm's long-deprecated v1beta3 API. Anyone still on a v1beta3 config needs to run kubeadm config migrate with the v1.35 kubeadm binary to produce a v1beta4 file before upgrading. The same change also removes the PublicKeysECDSA feature gate, superseded by v1beta4's ClusterConfiguration.EncryptionAlgorithm field.
scheduling.k8s.io drops v1alpha2 too, promoted to v1alpha3, per the change that retired scheduling.k8s.io's v1alpha2 API. Every v1alpha2 object needs to come out of kube-apiserver before the cluster update runs, or the upgrade fails on objects the new API server no longer recognizes. A related but separate API, workload-aware scheduling's Workload and PodGroup types, also moves off v1alpha2, this time up to v1beta1, in a separate pull request that graduated the workload-aware scheduling API to v1beta1. Same instruction applies: clear the v1alpha2 objects before upgrading from 1.36 to 1.37.
Beyond these, the release carries 67 enhancements in total, according to Kubernetes' own count of 1.37's enhancements, 16 graduating to Stable, 23 to Beta, 27 entering Alpha, and one deprecation or removal on top of what's covered here.
Kubernetes 1.37 isn't the only release this cycle that mixes one forced change into a pile of things you can ignore. Kotlin 2.4.20's own migration notes isolate a single Wasm compile-time break from a release that's otherwise safe to skip. Django's own dated support cutoff gives teams on 6.0 until April 2027 before security patches stop, a slower-moving deadline than a flag that kills kubelet on the spot. Next.js's 16.3 release notes and Android 17's per-app memory limits follow the same shape: read past the changelog's flat list before deciding what actually needs a sprint.
FAQ
Does kubelet log a warning or actually refuse to start if a removed flag is set?
It refuses to start. This isn't like earlier deprecation cycles where a flag prints a warning and keeps running. Kubernetes 1.37's changelog states plainly that kubelet fails to start if any of the 18 removed flags is still present, whether it's on the command line or inside a KubeletConfiguration file. There's no grace period and no compatibility switch to bring them back.
Which cAdvisor flag is still safe to keep?
Only --housekeeping-interval. It's easy to confuse with --global-housekeeping-interval, which is one of the 18 removed flags despite the similar name. If a config has the global- prefixed version, that one has to go.
Does this affect kubeadm-managed clusters differently than EKS, GKE, or AKS?
The flag removal itself is identical everywhere: any of the 18 flags on any node fails kubelet the same way regardless of how the cluster was provisioned. What differs is where the flags are likely hiding. On kubeadm clusters, check ClusterConfiguration.nodeRegistration.kubeletExtraArgs. On EKS, GKE, or AKS, check the node group's bootstrap script or launch template, since that layer isn't covered by upstream Kubernetes documentation at all.
What else got removed in Kubernetes 1.37 besides the cAdvisor flags?
Two other removals land in the same release. kubeadm drops its v1beta3 API entirely, after a deprecation window that opened in Kubernetes 1.31, so migrate with kubeadm config migrate to a v1beta4 config before upgrading. Separately, scheduling.k8s.io drops v1alpha2, promoted to v1alpha3, so any v1alpha2 objects need clearing from kube-apiserver first. Neither touches kubelet directly, but both will fail a cluster upgrade if skipped.
