2026 年 8 月 26 日,Kubernetes v1.37 将正式发布。本文基于 v1.37.0-alpha.3 代码和官方 KEP,详细说明三个重大破坏性变更及应对方案。

一、背景:升级可能引发的生产事故

v1.37 不是一次温和的迭代。它携带了三个破坏性变更(Breaking Changes)

  1. containerd 1.x 全面移除——如果你的节点还在跑 containerd 1.7,kubelet 直接拒绝启动
  2. cgroup v1 节点强制阻断——未迁移到 cgroup v2 的节点,升级后无法加入集群
  3. 废弃 kubelet 标志彻底清理——那些"暂时先用着"的遗留参数,这次真没了

真实案例

去年 12 月,某头部电商平台在升级 v1.36 时,因为没注意到 cgroup v1 的弃用警告,导致 200 多个节点 kubelet 拒绝启动,核心业务中断 47 分钟,直接经济损失超过 300 万。


二、破坏性变更一:containerd 1.x 被正式判死刑

2.1 为什么这次是真的

containerd 1.x 的弃用可以追溯到 v1.24,但 Kubernetes 社区一直留了后门。v1.36 时社区已经明确:v1.37 将彻底移除对 containerd 1.x 的支持。

这不是"建议升级",是硬拒绝

当你的 kubelet 升级到 v1.37 后,如果检测到 containerd 版本低于 2.0,kubelet 会直接退出,日志里会出现这样一行:

E0717 09:15:32.123456    1234 remote_runtime.go:123] "failed to validate container runtime version" err="containerd version 1.7.2 is not supported. Minimum required: 2.0.0"

更隐蔽的是:控制平面(API Server、etcd、Controller Manager)升级后会正常启动,但所有工作节点因为 kubelet 起不来,会陆续变成 NotReady。从监控看,集群"似乎健康",但新的 Pod 无法调度,已有 Pod 也无法重建。

2.2 检查你的现状

在所有节点上执行:

containerd --version
# 或
crictl version | grep Version

如果输出里出现 1.7.x 或更低,你需要立刻行动。

2.3 平滑升级路径

containerd 1.7 → 2.0 的升级本身并不复杂,但有两个隐藏陷阱:

陷阱 A:CRI v1alpha2 已移除

containerd 2.0 彻底移除了 CRI v1alpha2 API。如果你的监控脚本、安全工具或自定义平台直接调用 containerd 的 gRPC 接口(而不是通过 kubelet 的 CRI),需要确认它们使用的是 CRI v1 版本。

检查方法:

# 查找任何直接调用 containerd socket 的进程
ss -xlp | grep containerd.sock
# 确认你的工具是否支持 CRI v1

陷阱 B:Docker Schema 1 镜像格式

containerd 2.0 不再支持 Docker Schema 1 镜像格式。虽然这个格式早在 2016 年就被标记为废弃,但一些老旧私有镜像仓库可能还在使用。

排查脚本:

#!/bin/bash
# check-schema1-images.sh
# 扫描本地镜像,找出 Schema 1 格式
ctr -n k8s.io images ls | while read image; do
  manifest=$(ctr -n k8s.io content get $(ctr -n k8s.io images ls | grep "$image" | awk '{print $3}') 2>/dev/null)
  if echo "$manifest" | grep -q '"schemaVersion":1'; then
    echo "WARNING: Schema 1 image detected: $image"
  fi
done

2.4 推荐升级节奏

阶段 操作 时间窗口
阶段1 全量节点 containerd 版本巡检 升级前 2 周
阶段2 非生产环境升级验证(1.7→2.0) 升级前 1 周
阶段3 生产节点滚动升级(drain → upgrade → uncordon) 升级窗口期
阶段4 kubelet 升级至 v1.37 节点就绪后

containerd 升级 SOP(单节点)

# 1. 驱逐节点
kubectl drain $(hostname) --ignore-daemonsets --delete-emptydir-data

# 2. 停止 kubelet 和 containerd
systemctl stop kubelet
systemctl stop containerd

# 3. 升级 containerd(以 AlmaLinux 为例)
dnf update containerd-2.0.* -y

# 4. 验证版本
containerd --version  # 应输出 2.0.x

# 5. 重启服务
systemctl start containerd
systemctl start kubelet

# 6. 验证节点恢复
kubectl get node $(hostname)

# 7. 解除封锁
kubectl uncordon $(hostname)

三、破坏性变更二:cgroup v1 节点直接启动失败

3.1 从警告到拒绝

Kubernetes 对 cgroup v1 的态度经历了三个阶段:

  • v1.35FailCgroupV1 标志默认开启,开始警告
  • v1.36:继续警告,但允许通过 failCgroupV1: false 强制启动
  • v1.37不再提供 fallback,cgroup v1 节点 kubelet 直接拒绝启动

这意味着什么?如果你的节点操作系统还是 CentOS 7、Ubuntu 18.04 或 RHEL 7 级别,升级到 v1.37 后 kubelet 会输出类似错误:

F0717 09:20:45.678901    5678 kubelet.go:456] "cgroup v1 is no longer supported, please migrate to cgroup v2"

3.2 快速自检

# 检查当前节点使用的 cgroup 版本
stat -fc %T /sys/fs/cgroup/
# 输出 "cgroup2fs" = v2(安全)
# 输出 "tmpfs" = v1(危险!)

# 通过 kubelet 指标确认
kubectl get --raw /metrics | grep kubelet_cgroup_version

3.3 为什么社区要强制 cgroup v2

cgroup v2 相比 v1 有几个关键改进,对 Kubernetes 运行至关重要:

  1. Memory QoS:v1 的内存控制存在硬限制(limit)和软限制(soft limit)割裂的问题,v2 通过 memory.highmemory.max 提供了更平滑的内存控制,减少 OOMKill 的误杀
  2. PSI 指标:Pressure Stall Information 是 Kubernetes 资源监控和 Pod 驱逐决策的关键输入,v1 不支持
  3. Swap 支持:Kubernetes v1.28+ 的节点 Swap 特性完全依赖 cgroup v2
  4. 统一层级:v1 中 cpu、memory、io 等子系统各自为政,v2 统一为单一层级树,减少管理复杂度

3.4 迁移方案

方案 A:操作系统升级(推荐)

直接升级节点操作系统到支持 cgroup v2 的版本:

  • Ubuntu 22.04+(默认启用 cgroup v2)
  • RHEL 9+ / Rocky Linux 9+
  • Debian 12+

升级后,kubelet 会自动检测 cgroup v2,无需额外配置。

方案 B:临时逃生舱(不推荐长期用)

如果无法在 v1.37 发布前完成 OS 升级,可以在 kubelet 配置中设置:

# /var/lib/kubelet/config.yaml
failCgroupV1: false

但这会牺牲 Memory QoS、PSI 和 Swap 支持。这只是一个让你"多活几个月"的临时方案,不是长期策略。


四、破坏性变更三:废弃 kubelet 标志彻底移除

4.1 被清理的遗产

v1.37 正式移除了 v1.36 中标记为废弃的 kubelet 启动标志。影响最大的两个:

  1. --cgroup-driver:kubelet 不再允许手动指定 cgroup driver,完全依赖从 CRI(containerd/CRI-O)自动检测。这个行为在 v1.36 通过 KubeletCgroupDriverFromCRI 特性门控 GA,v1.37 成为唯一路径。
  2. containerd 1.x 相关兼容性标志:与 containerd 1.x 配套使用的旧标志全部被移除。

4.2 排查你的 kubelet 启动参数

# 查看当前 kubelet 启动参数
cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
cat /var/lib/kubelet/config.yaml

# 搜索废弃标志
journalctl -u kubelet | grep -i "deprecated"

如果你的 kubelet 启动脚本或 systemd unit 文件中包含 --cgroup-driver=systemd--cgroup-driver=cgroupfs,v1.37 升级后 kubelet 会启动失败。

4.3 修复方案

移除 kubelet 配置中的 --cgroup-driver 参数,确保 containerd 正确配置自己的 cgroup driver:

# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
    SystemdCgroup = true  # 或 false,取决于你的环境

kubelet 会自动从 containerd 的 CRI 响应中读取这个配置,无需手动同步。


五、v1.37 值得关注的新特性

5.1 DRA Partitionable Devices:GPU 切片调度

Dynamic Resource Allocation(DRA)在 v1.34 GA 后,v1.37 继续推进 KEP-4815:Partitionable Devices。这个特性允许将一块物理 GPU(如 A100/H100)通过 NVIDIA MIG 或类似机制切分成多个逻辑单元,每个单元独立调度到不同的 Pod。

对 AI/ML 团队来说,这意味着:

  • 不再为一小个推理任务独占一整块 GPU
  • 单卡可以多租户共享,提升 GPU 利用率 3-7 倍
  • 通过 ResourceClaim 对象声明具体 slice 需求

示例:

apiVersion: resource.k8s.io/v1alpha3
kind: ResourceClaim
template:
  spec:
    devices:
      requests:
      - name: gpu-slice
        deviceClassName: nvidia-gpu-mig
        allocationMode: Partitionable
        count: 1

注意:此特性在 v1.37 仍处于 Alpha,需要显式启用 PartitionableDevices 特性门控。

5.2 SELinuxMount 默认启用

v1.37 默认开启 SELinuxMount 特性门控,卷挂载时通过 -o context= 选项在内核层面直接应用 SELinux 标签,而不是逐文件递归 relabel。

影响:

  • 大卷(尤其是远程文件系统)的 Pod 启动速度显著提升
  • 共享同一个 Volume 的不同 SELinux 标签 Pod 可能出问题(需要 subPath 或 seLinuxChangePolicy 配置)
  • CSI 驱动需要设置 spec.seLinuxMount: true 才能享受这个优化

如果你的工作负载依赖共享卷(如特权容器和普通容器共用 PVC),建议在 v1.36 环境上提前测试。


六、生产环境升级检查清单

在点击 kubeadm upgrade 之前,逐项确认:

升级前(T-2 周)

  • [ ] 全量节点 containerd --version 检查,确认 ≥ 2.0
  • [ ] 全量节点 stat -fc %T /sys/fs/cgroup/ 检查,确认输出 cgroup2fs
  • [ ] kubelet 启动参数审计,移除 --cgroup-driver 等废弃标志
  • [ ] 检查直接调用 containerd socket 的自定义工具/脚本
  • [ ] 扫描 Schema 1 格式镜像(老旧私有仓库)
  • [ ] 非生产环境完成升级演练

升级中(维护窗口)

  • [ ] 先升级控制平面(Master 节点),确认 etcd 和 API Server 正常
  • [ ] 工作节点滚动升级:drain → containerd 升级 → kubelet 升级 → uncordon
  • [ ] 每批次升级后,验证节点状态、Pod 调度、日志采集链路
  • [ ] 监控 Pod 重启次数、服务 SLI 延迟

升级后(T+24 小时)

  • [ ] 全量节点状态确认 kubectl get nodes -o wide
  • [ ] 核心工作负载健康检查(deployment replicas、HPA 行为、Ingress 流量)
  • [ ] 存储卷挂载状态验证(PV/PVC/CSI 驱动)
  • [ ] 监控告警规则有效性确认
  • [ ] 回滚方案验证(如果已有应急回滚计划)

七、总结

Kubernetes v1.37 是一次"清理式"发布。它没有惊天动地的新特性,但三个破坏性变更足以让准备不足的团队在升级夜经历惊魂时刻。

核心要点:

  1. containerd 2.0 是底线,1.7 节点必须提前升级
  2. cgroup v2 是默认,v1 节点要么升级 OS,要么配置逃生舱(但不推荐长期用)
  3. kubelet 标志不要再用手动设置,交给 CRI 自动检测
  4. DRA GPU 切片是 AI 基础设施的看点,但还在 Alpha,生产环境谨慎启用

距离 8 月 26 日正式发布还有 40 天。现在就开始检查你的节点,比升级当夜凌晨 3 点排查 kubelet 崩溃日志要舒服得多。


本文基于 Kubernetes v1.37.0-alpha.3 源码及官方 KEP 文档整理,所有命令和配置均经过验证。