Skip to main content

The Kubernetes 1.37 Containerd Deadline That Doesn't Exist: A Fleet Upgrade Verification Playbook

10 min readDora NodaDora Noda
Share
On this page

Sometime in the last two months, your team may have scheduled a containerd migration that Kubernetes 1.37 never asked for. Multiple upgrade guides state, confidently, that Kubernetes 1.37 dropped support for containerd 1.x and that any node still running it will fail to boot a v1.37 kubelet. The official changelog says the opposite: the removal was deferred to 1.38, months before 1.37 shipped.

Here is the part that should bother you more than the error itself. While teams burned validation cycles on a fictional deadline, the real containerd deadline — the end of containerd 1.7 maintenance — quietly arrived on September 30, 2026, two weeks ago. A louder, wrong deadline crowded out a quieter, correct one. This post gives you the verdict with receipts, the real 1.37 gates you should have been checking instead, and a 15-minute pre-rollout check so your fleet never schedules work against a phantom gate again.

No, 1.37 will not refuse your containerd 1.x nodes​

The verdict first, since it is the reason you opened this. Kubernetes 1.37, released August 26, 2026, still boots fine on containerd 1.x nodes. The kubelet behavior that would break them — the removal of the CRI fallback for runtimes that predate the RuntimeConfig RPC — was explicitly postponed out of this release.

The receipt is one line in the 1.37 changelog, from PR #139121, merged May 22, 2026: "Deferred the deprecation removal timeline for the configuration flags (and the related fallback behavior) from v1.37 to v1.38 to align with containerd v1.7 support." And it was not the first postponement: PR #136846 had already deferred the same removal from 1.36 to 1.37. The deadline moved twice before 1.37 ever shipped.

What is the "fallback" in question? Under KEP-4033, "Discover cgroup driver from CRI," the kubelet asks the runtime for cgroup-driver configuration over the CRI. Containerd 1.x never implemented that RPC, so the kubelet falls back to its own --cgroup-driver flag on those nodes. Removing the fallback is what would strand 1.x nodes — and the container-runtimes documentation confirms the removal lands in 1.38, not 1.37: "In Kubernetes 1.38, this fallback behavior will be dropped, and older versions of containerd will fail with newer kubelets." That sentence only makes sense if the fallback still works today.

The 15-minute pre-rollout check​

Before the forensics, here is the habit this whole incident argues for. Run it against every scary upgrade claim before you touch a node image. Each step below is demonstrated on this exact case in the exhibits that follow.

  1. Read the "Urgent Upgrade Notes" first, not a guide. Every changelog has a section literally titled "(No, really, you MUST read this before you upgrade)." If the claimed gate is not in there, treat the claim as unproven. The containerd claim is absent from 1.37's notes; the four real gates are all there (Exhibit C).
  2. Grep the changelog for your runtime. Download the changelog and search it directly instead of trusting a summary: grep -n -i "containerd" CHANGELOG-1.37.md The two hits that matter are the deferral lines for #136846 and #139121 — each stating the removal moved out, not in.
  3. Ask the kubelet, not the blog. The kubelet exposes a gauge reporting the Kubernetes version at which the node's current CRI loses support. Scrape it per node and grep for the losing-support signal: kubectl get --raw "/api/v1/nodes/NODE-NAME/proxy/metrics" | grep cri_losing_support If the reported version is later than the release you are rolling to, the gate does not apply to that node yet.
  4. Audit your kubelet flags against the removal list. Real "kubelet will fail to start" gates in 1.37 are flag removals, not runtime-version checks. Diff your kubeadm-flags.env, systemd drop-ins, and kubelet config against the 18 removed cAdvisor flags (Exhibit C) and delete any matches.
  5. Canary one node image before the fleet. Roll the new kubelet onto a single node carrying your oldest runtime and watch kubelet startup. A phantom gate costs you one canary; a trusted-but-wrong guide costs you a fleet-wide rebuild.

Fifteen minutes, five steps, zero rebuilt images. Now the evidence for why each step exists.

Exhibit A: the claim, and where it lives​

On September 11, 2026, an investigation by NTCTech found at least three independent sites — a release-tracking aggregator, a consultancy news page, and a general upgrade-guide site — telling readers that 1.37 dropped containerd 1.x support and that nodes still running it would fail to boot the new kubelet. That is the precise shape of a scary upgrade gate: a version number, a hard consequence, an implied "migrate now."

The damning detail is not that these sites lacked sources. One of them cited the exact changelog file that disproved its own conclusion in its Sources section while stating the opposite in its FAQ. A second linked that same changelog as its canonical "Release notes" reference, then ran body copy claiming the removal already happened. The citation survived fully intact — linked, listed, footnoted — after fidelity to what it said was gone. Citation is not fidelity, and a Sources footer reads as due diligence whether or not the adjacent sentence reflects the source.

The myth is still propagating. A 1.37 guide published October 1 — three weeks after the debunk — states flatly: "Container runtimes must use containerd 2.x – containerd 1.x is no longer supported." That is checklist step 1 failing in the wild: the claim never appears in the Urgent Upgrade Notes, so it should never have cleared "unproven."

Exhibit B: how a wrong deadline outruns a right changelog​

Nobody faked anything here, which is what makes the pattern worth naming. The changelog was accurate and published first, on May 22. The wrong interpretation still won, because the layers between a changelog and your runbook optimize for different things: the changelog for accuracy, the day-one upgrade post for speed to publish, the SEO guide for discoverability, the aggregator for simplicity. An alarm ("1.37 removes support, migrate now") outranks a postponement ("the breaking change you were warned about isn't happening yet") every time, because urgency drives clicks and corrections do not.

Once one site publishes the alarm, later sites cite that site instead of going back to the changelog — which is how an October 1 guide can repeat a claim debunked on September 11 without anyone in the chain re-reading the primary source. By the time anyone actually upgrades a cluster and watches the 1.x node boot fine, the deadline narrative has already been copied into internal FAQs, migration runbooks, and planning docs. Verification arrives too late to interrupt propagation; it arrives just in time to explain what already happened. That is why the check in step 2 goes to the changelog file itself, not to any page that summarizes it.

Exhibit C: what 1.37 actually gates​

Here is what the 15-minute check surfaces instead of the phantom: the four ACTION REQUIRED items in 1.37's Urgent Upgrade Notes, plus the genuine kubelet-won't-start list. If your team audited any of these, the 1.37 cycle was well spent.

Real gateWhat it requires
SELinuxMount graduates to GA, enabled by defaultSELinux clusters must audit workloads for volume-labeling breakage before upgrading (#139956)
scheduling.k8s.io/v1alpha2 removed entirelyDelete all v1alpha2 objects from the API server before the cluster update (#138572)
eventRecordQPS: 0 now means unlimitedAnyone relying on the old default must set an explicit non-zero value (#117119)
Kubelet logs effective config at startupRestrict the nodes/logs ClusterRole; config details now appear in logs (#139837)
18 cAdvisor kubelet flags removedKubelet fails to start with unknown flag if any are set, including --containerd and --containerd-namespace (#139870)

Note the irony in the last row. The October 1 guide that carries the false containerd claim documents this real flag removal correctly, in the same section. A team that ran checklist step 4 — diff your flags against the removal list — would have caught the gate that actually breaks kubelet startup while ignoring the version claim that does not. Phantom gates and real gates travel together; only the primary source tells them apart. Conspicuously, the flag list even includes --containerd itself — a cAdvisor flag, not a runtime-version check — which may be one more reason the "containerd" keyword kept tripping automated summaries toward the wrong conclusion.

Exhibit D: the deadline that does exist​

Containerd's own release table puts containerd 1.7 end-of-life at September 30, 2026. That date passed two weeks ago. The maintainer has stopped shipping patches. That is a real deadline — but it is a support-policy deadline, not a Kubernetes enforcement deadline. Nothing in the 1.37 or upcoming 1.38 kubelet forces a runtime version on that date; the distinction between "a maintainer chose a calendar date" and "a kubelet enforces a behavior change" is the entire confusion in miniature, and conflating the two is exactly how a support date gets mistaken for a hard technical wall.

The practical question is where to land, and here recency beats version-number superstition. Not every 2.x line buys the same runway:

containerd lineStatusMaintained until
1.7End of lifeSeptember 30, 2026
2.1End of lifeJuly 3, 2026
2.2ActiveNovember 6, 2026
2.0LTSMarch 2027
2.4ActiveMay 16, 2027
2.3LTSApril 30, 2028

Migrating to 2.2 today to say you "moved to 2.x" buys about three weeks of support. The current long-term-support line is 2.3, maintained until April 30, 2028 — that is the destination worth scheduling validation cycles against. And the honest sequencing is: the containerd migration is driven by the September 30 support date and your own patch policy, while the Kubernetes 1.38 upgrade (whenever your fleet takes it) is what eventually enforces the runtime floor. Two deadlines, two owners, two timelines.

Why self-hosted fleets need this habit most​

A managed-node customer inherits a vendor's preflight: EKS, GKE, or AKS validates the kubelet against the runtime it ships, and a phantom gate dies quietly in the vendor's test matrix before it ever reaches your runbook. A self-hosted fleet gets no such filter. You build the node image, you pin the containerd version in it, and when a guide says "1.37 requires 2.x," the cost of belief is a rebuilt image, a revalidated workload matrix, and a compressed rollout — all against a date nothing required.

That asymmetry cuts both ways, though. The same ownership that exposes you to phantom gates is what makes the 15-minute check cheap: your node images are version-controlled artifacts, your oldest runtime is a query away, and a single canary node costs you almost nothing. The discipline is simply to spend the fifteen minutes before spending the sprint. Diff the claimed gate against the upstream changelog, ask the kubelet's own metric what it thinks of your nodes, and let the primary source — not the most confident summary — decide what gets rebuilt.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex