Summary
core/ links github.com/containerd/containerd/v2 v2.2.7 (chosen in #64 over v2.3.4). This issue tracks moving to containerd 2.3 LTS, which is gated on raising the minimum supported node containerd version.
Retargeted from "2.3.x" to "2.3 LTS", with a hard deadline added. The original framing treated this as an open-ended "move when AKS and EKS catch up." Upstream's RELEASES.md support horizons make it time-bound: the compatible fallback path expires in March 2027, after which this move is forced regardless of what AKS and EKS ship.
Why the target is 2.3, and why 2.4 must be skipped
| Release |
Status |
End of Life |
| 2.0 |
LTS (extended) |
March 2027 |
| 2.1 |
End of Life |
July 3, 2026 |
| 2.2 — linked today |
Active (regular) |
November 6, 2026 |
| 2.3 — target |
LTS |
April 30, 2028 |
| 2.4 |
Future |
April 26, 2027 (tentative) |
2.3 is the LTS line. 2.4 is a regular 8-month release whose EOL (Apr 2027) lands a year before 2.3's, so bumping to 2.4 when it lands would be strictly worse than 2.3 and should not be treated as a future target. Since containerd 2.3 (April 2026) minor releases follow a 4-month cadence with one LTS per year — so the next LTS after 2.3 is roughly a year out.
The blocker: bootstrap handshake format
A shim linked against 2.3.x cannot talk to a daemon older than 2.3. The shim writes its bootstrap params to stdout in a format the daemon parses:
| Linked version |
pkg/shim/shim.go writes |
| v2.0.10 |
json.Marshal(¶ms) |
| v2.1.6 |
json.Marshal(¶ms) |
| v2.2.7 |
json.Marshal(¶ms) (shim.go:295) |
| v2.3.4 |
proto.Marshal(result) (shim.go:312) |
Against the provisioner's containerd 2.0.5, a v2.3.4-linked shim fails at startup before any task service is reached:
failed to start shim: start failed: failed to create TTRPC connection:
unsupported protocol: ^H^C^RYunix
Those are protobuf wire bytes (\x08\x03 = Version 3, \x12\x59 = 89-byte string, then unix://...) being read as JSON. This surfaced as E2E tier 08/09/12/14/15 failures.
There is no supported way to build a v2.3.4-linked shim that emits legacy JSON. The shim-side compat layer (pkg/shim/compat.go, readBootstrapParamsFromDeprecatedFields) is input-only; the stdout write is unconditional.
The v2.3.4 daemon does accept legacy JSON, via an explicit fallback in core/runtime/v2/shim.go:236-245:
// Fallback to legacy parsing for backward compatibility with legacy shims that return the address as a plain string or JSON.
So daemon coverage is a strict superset in one direction, and staying on 2.2.7 remains correct today:
| Shim linked against |
Runs on daemon |
| v2.2.7 (JSON) |
2.0, 2.1, 2.2, and 2.3+ |
| v2.3.4 (protobuf) |
2.3+ only |
The deadline this issue previously missed
Every JSON-emitting line is on its way out. After Nov 6, 2026 (2.2 EOL), the only supported JSON-emitting line is 2.0 LTS, and that ends March 2027.
now ──────── Nov 6 2026 ──────── Mar 2027 ──────── Apr 30 2028
2.2.7 OK 2.2 EOL 2.0 LTS EOL 2.3 LTS EOL
only 2.0 LTS no supported
still JSON JSON line left
→ 2.3 forced
Continuing to link an EOL containerd means no upstream security backports for pkg/shim and the runc task service we embed. So the choice is not "move when convenient" — it is move to 2.3 LTS by March 2027, or knowingly ship an unsupported containerd library.
Note also that falling back to 2.0 LTS between Nov 2026 and Mar 2027 would mean regressing containerd/api v1.10.0 → v1.8.0 and is a dead end four months later. It is not a recommended path; it is listed only to show the fallback is exhausted.
Node-image situation (the original blocker, now self-clearing)
| Platform |
containerd |
Upstream status |
2.3-linked shim? |
| AKS Ubuntu 24.04 (node image 202601.27.0) |
2.1.6 |
already EOL (Jul 3, 2026) |
❌ |
| EKS AL2023 (release v20260827) |
2.2.5 |
EOL Nov 6, 2026 |
❌ |
| Ubuntu 22.04 / 24.04 distro package |
2.2.1 |
EOL Nov 6, 2026 |
❌ |
Brewlet provisioner (provisioner/Dockerfile:21) |
2.0.5 |
LTS to Mar 2027 |
❌ |
| kind node base image |
2.3.4 |
LTS to Apr 2028 |
✅ |
Both managed offerings are running containerd that is already EOL or EOL within two months. They are being forced forward on roughly the same clock we are, and 2.3 LTS (supported to Apr 2028) is the natural landing spot for both. The blocker is likely to clear itself well before March 2027 — but the deadline holds either way.
Knock-on: containerd/api stays at v1.10.0
Each containerd line pins its own api: 2.0.10 → v1.8.0, 2.1.6 → v1.9.0, 2.2.7 → v1.10.0, 2.3.4 → v1.11.1.
Dependabot PR #51 originally tried to take api to v1.11.1; it was merged with an explicit pin to v1.10.0 because v1.11.1 was incompatible with the then-current containerd v1.7.34. #64 removed that manual pin (resolution is now driven by the containerd module), but the effective version is still v1.10.0. Reaching api v1.11.1 requires the 2.3 move, and therefore this same node-floor decision.
Expect Dependabot to keep proposing containerd/api v1.11.x until then; close those with a reference to this issue rather than merging.
Decision triggers
Move to containerd/v2 2.3.x when the earliest of these occurs:
- AKS and EKS default node images ship containerd 2.3+ — the clean path; recheck at the Nov 2026 checkpoint below.
- March 2027 — hard deadline. 2.0 LTS goes EOL and no supported JSON-emitting line remains. Move regardless of node images, accepting the floor raise.
- A deliberate earlier decision to raise Brewlet's documented minimum node containerd to 2.3+.
Checkpoint: November 2026. Re-read AKS and EKS node image release notes when 2.2 goes EOL and re-evaluate. Do not bump to 2.4 in the meantime (see above).
Work required when it happens
- Bump
core/go.mod to containerd/v2 v2.3.x and let api resolve to v1.11.1. The Go floor becomes 1.26.3; core/go.mod:3 currently declares go 1.26 and is the go-version-file for the ci, e2e and release workflows, which also build kubernetes/ (go 1.26.0) — raise deliberately and check GOTOOLCHAIN: local still resolves.
- Raise
CONTAINERD_VERSION in provisioner/Dockerfile:21 (currently 2.0.5).
- Update the version gate in
provisioner/entrypoint.sh (require_containerd_image_identity, die at line 427) and its test in provisioner/entrypoint_test.sh.
- Update the 2.0+ prose in
specs/SPECIFICATION.md:638, docs/installation.md:27, docs/troubleshooting.md, provisioner/README.md:13.
- Re-verify E2E tiers 08, 09, 12, 14, 15 — the ones that caught this.
Original context: filed as follow-up to #64. Module-level version facts verified against upstream tags v2.0.10 / v2.1.6 / v2.2.2 / v2.2.7 / v2.3.4 on 2026-09-04. Support horizons and cadence re-verified against upstream RELEASES.md, and repository line references re-verified against main, on 2026-09-07.
Summary
core/linksgithub.com/containerd/containerd/v2v2.2.7 (chosen in #64 over v2.3.4). This issue tracks moving to containerd 2.3 LTS, which is gated on raising the minimum supported node containerd version.Retargeted from "2.3.x" to "2.3 LTS", with a hard deadline added. The original framing treated this as an open-ended "move when AKS and EKS catch up." Upstream's RELEASES.md support horizons make it time-bound: the compatible fallback path expires in March 2027, after which this move is forced regardless of what AKS and EKS ship.
Why the target is 2.3, and why 2.4 must be skipped
2.3 is the LTS line. 2.4 is a regular 8-month release whose EOL (Apr 2027) lands a year before 2.3's, so bumping to 2.4 when it lands would be strictly worse than 2.3 and should not be treated as a future target. Since containerd 2.3 (April 2026) minor releases follow a 4-month cadence with one LTS per year — so the next LTS after 2.3 is roughly a year out.
The blocker: bootstrap handshake format
A shim linked against 2.3.x cannot talk to a daemon older than 2.3. The shim writes its bootstrap params to stdout in a format the daemon parses:
pkg/shim/shim.gowritesjson.Marshal(¶ms)json.Marshal(¶ms)json.Marshal(¶ms)(shim.go:295)proto.Marshal(result)(shim.go:312)Against the provisioner's containerd 2.0.5, a v2.3.4-linked shim fails at startup before any task service is reached:
Those are protobuf wire bytes (
\x08\x03= Version 3,\x12\x59= 89-byte string, thenunix://...) being read as JSON. This surfaced as E2E tier 08/09/12/14/15 failures.There is no supported way to build a v2.3.4-linked shim that emits legacy JSON. The shim-side compat layer (
pkg/shim/compat.go,readBootstrapParamsFromDeprecatedFields) is input-only; the stdout write is unconditional.The v2.3.4 daemon does accept legacy JSON, via an explicit fallback in
core/runtime/v2/shim.go:236-245:So daemon coverage is a strict superset in one direction, and staying on 2.2.7 remains correct today:
The deadline this issue previously missed
Every JSON-emitting line is on its way out. After Nov 6, 2026 (2.2 EOL), the only supported JSON-emitting line is 2.0 LTS, and that ends March 2027.
Continuing to link an EOL containerd means no upstream security backports for
pkg/shimand the runc task service we embed. So the choice is not "move when convenient" — it is move to 2.3 LTS by March 2027, or knowingly ship an unsupported containerd library.Note also that falling back to 2.0 LTS between Nov 2026 and Mar 2027 would mean regressing
containerd/apiv1.10.0 → v1.8.0 and is a dead end four months later. It is not a recommended path; it is listed only to show the fallback is exhausted.Node-image situation (the original blocker, now self-clearing)
provisioner/Dockerfile:21)Both managed offerings are running containerd that is already EOL or EOL within two months. They are being forced forward on roughly the same clock we are, and 2.3 LTS (supported to Apr 2028) is the natural landing spot for both. The blocker is likely to clear itself well before March 2027 — but the deadline holds either way.
Knock-on:
containerd/apistays at v1.10.0Each containerd line pins its own
api: 2.0.10 → v1.8.0, 2.1.6 → v1.9.0, 2.2.7 → v1.10.0, 2.3.4 → v1.11.1.Dependabot PR #51 originally tried to take
apito v1.11.1; it was merged with an explicit pin to v1.10.0 because v1.11.1 was incompatible with the then-current containerd v1.7.34. #64 removed that manual pin (resolution is now driven by the containerd module), but the effective version is still v1.10.0. Reachingapiv1.11.1 requires the 2.3 move, and therefore this same node-floor decision.Expect Dependabot to keep proposing
containerd/apiv1.11.x until then; close those with a reference to this issue rather than merging.Decision triggers
Move to containerd/v2 2.3.x when the earliest of these occurs:
Checkpoint: November 2026. Re-read AKS and EKS node image release notes when 2.2 goes EOL and re-evaluate. Do not bump to 2.4 in the meantime (see above).
Work required when it happens
core/go.modtocontainerd/v2 v2.3.xand letapiresolve to v1.11.1. The Go floor becomes 1.26.3;core/go.mod:3currently declaresgo 1.26and is thego-version-filefor theci,e2eandreleaseworkflows, which also buildkubernetes/(go 1.26.0) — raise deliberately and checkGOTOOLCHAIN: localstill resolves.CONTAINERD_VERSIONinprovisioner/Dockerfile:21(currently 2.0.5).provisioner/entrypoint.sh(require_containerd_image_identity,dieat line 427) and its test inprovisioner/entrypoint_test.sh.specs/SPECIFICATION.md:638,docs/installation.md:27,docs/troubleshooting.md,provisioner/README.md:13.Original context: filed as follow-up to #64. Module-level version facts verified against upstream tags v2.0.10 / v2.1.6 / v2.2.2 / v2.2.7 / v2.3.4 on 2026-09-04. Support horizons and cadence re-verified against upstream
RELEASES.md, and repository line references re-verified againstmain, on 2026-09-07.