Kubernetes v1.36 深度解析:代号 Haru,从容器编排引擎到 AI 基础设施控制面的蜕变
背景:2026年Kubernetes的成人礼
2026年4月22日,Kubernetes v1.36 正式发布,代号 Haru(日语"晴れ",意为晴空)。这个版本有106家公司和491位个人贡献者参与,提交了70项增强——18项进入 Stable,25项进入 Beta,25项全新的 Alpha 功能。
但数字不是重点。重点是:Kubernetes v1.36 是目前为止最具"方向感"的一个版本。它不再只是"一个容器编排工具"的版本迭代,而是 Kubernetes 作为AI基础设施控制面身份的正式宣告。同时,它在安全方面也拿出了历年最激进的默认配置收紧策略。
这篇文章,我们从架构深处出发,把 v1.36 的每个重要变化讲透,配代码、配实战场景。不废话,直接开始。
一、AI 工作负载:Kubernetes 不再只是"跑容器"了
1.1 分布式训练的根本矛盾:Pod 独立调度之痛
在 Kubernetes 跑 AI 分布式训练任务(比如 PyTorch 的 torchrun 分布式训练),你通常会部署 N 个 Pod 作为 worker 进程。以 8 卡分布式训练为例:8 个 Pod 各自请求 1 张 GPU,协同完成一个训练任务。
问题来了:Kubernetes 调度器在做抢占(Preemption)时,是 Pod-by-Pod 操作的。当高优先级任务需要资源时,调度器会逐个驱逐低优先级 Pod,直到腾出足够空间。
这在 AI 训练场景下是灾难性的——
假设 8 卡训练任务正在运行,调度器为了腾出 2 个 GPU,驱逐了 2 个低优先级 Pod。现在情况变成:6 卡在运行,2 卡空闲。由于训练任务需要所有 worker 同时就绪才能推进,6 卡的状态下任务彻底卡死:6 个进程在等待永远无法返回的集合通信(AllReduce)。
这就是分布式训练的部分抢占失败模式(Partial Preemption Failure Mode):资源被浪费了,但高优先级任务也没能真正完成。
1.2 工作负载感知抢占(Workload-Aware Preemption):原子性调度组
v1.36 引入了 Alpha 阶段的新机制来解决这个问题——PodGroup 作为原子抢占单元。
核心思路:将一组相关的 Pod(通过 PodGroup API 关联)视为一个逻辑整体,只有在能够一次性为整个高优先级组腾出足够资源时,才执行抢占。
# 定义一个 PodGroup(v1.36 Alpha,PodGroup API)
apiVersion: scheduling.sigs.k8s.io/v1alpha1
kind: PodGroup
metadata:
name: distributed-training-pg
namespace: ml
spec:
priorityClassName: high-priority-training
minMember: 8 # 最少需要 8 个 Pod 同时调度
---
# Job 引用该 PodGroup
apiVersion: batch/v1
kind: Job
metadata:
name: distributed-training-job
namespace: ml
spec:
schedulingGang:
podGroupRef:
name: distributed-training-pg
# DisruptionMode 决定抢占策略
disruptionMode: PodGroup # 只能是 PodGroup 或 IndividualPods
parallelism: 8
completions: 8
template:
spec:
priorityClassName: high-priority-training
containers:
- name: trainer
image: pytorch/pytorch:2.4.0-cuda12.1
command: ["torchrun", "--nproc_per_node=1", "train.py"]
resources:
limits:
nvidia.com/gpu: "1"
memory: "32Gi"
requests:
nvidia.com/gpu: "1"
memory: "32Gi"
关键参数 disruptionMode:
PodGroup(推荐):整组一起调度/抢占,要么全有要么全无IndividualPods:回退到传统的 Pod-by-Pod 调度(向后兼容)
PodGroup 还会继承一个 priorityClassName(组优先级),这个组优先级会覆盖组内各 Pod 的单独优先级。调度器在计算抢占时会使用组优先级来做决策。
这个改动意味着:运行大型 GPU 集群的团队,终于可以用 Kubernetes 原生能力来做"高优先级训练任务优先、低优先级任务整体让步"的调度策略了,而不必自己写自定义调度器。
1.3 Gang 调度 API:从 Alpha 到 Beta
v1.35 引入的 Gang 调度 API 在 v1.36 正式进入 Beta 阶段,且默认开启。
Gang 调度的核心语义是:除非一组 Pod 能够同时调度成功(满足最小数量要求),否则一个都不调度。避免"调度了 7 个 Pod 但第 8 个永远调不上,导致 7 个 Pod 空转等待"的资源浪费。
v1.36 的新改进在于:PodGroup 调度周期现在可以原子性评估整个组——要么全部绑定,要么一个都不绑定。
1.4 DRA(动态资源分配):GPU 共享与分区
Kubernetes 传统 GPU 分配是"整数分配"模型:申请一张 GPU 就分配整卡。如果你的模型只需要半张 GPU(比如用张量并行),传统模型根本无法高效利用。
v1.36 中,DRA 的三个关键子功能默认开启(无需手动配置特性门控):
| 功能 | 说明 |
|---|---|
| DRA 可分区设备 | GPU/加速器可以按分区分配给不同 Pod |
| DRA 可消耗容量 | 支持 fractional GPU 分配 |
| DRA 设备污点与容忍 | 调度器理解加速器的资源属性 |
这意味着你可以用 Kubernetes 原生机制跑张量并行、Pipeline 并行等需要"半卡"或"部分资源"的 AI 工作负载。
VMware Cloud Foundation 博客的说法很到位:"通过采用更规范化的实现方式,Kubernetes 让调度器能够更清晰地识别 GPU 及 AI 加速器的专属资源需求,大幅降低了多节点 AI 部署的复杂度。"
1.5 Pod 级资源原地垂直扩缩容(In-Place Vertical Scaling)
进入 Beta 并默认启用的另一个重磅功能:在不重启容器的情况下调整 CPU 和内存配额。
这在 AI 训练中意味着什么?你的 Job 队列控制器可以:
- 暂停正在运行的作业
- 调整 CPU/内存/GPU 请求(适配集群当前可用容量)
- 恢复作业运行
不需要销毁 Pod,不需要重新拉镜像,不需要重新下载数据集。
新增的 ResizeDeferred 事件类型处理节点容量不足的情况:当无法立即执行扩缩容时,Pod 继续按现有规格运行,等节点资源空闲后 Kubelet 自动重试。
// 伪代码:队列控制器的原地扩缩逻辑
func (q *QueueController) adjustJobResources(job *batch.Job, availableCores int) error {
podSpec := job.Spec.Template.Spec
// 获取当前容器资源请求
currentCPU := podSpec.Containers[0].Resources.Requests["cpu"]
// 根据集群实时容量调整(向下)
newCPU := min(currentCPU, resource.MustParse(fmt.Sprintf("%d", availableCores)))
// 修改 Pod 资源请求(原地,无需重建)
podSpec.Containers[0].Resources.Requests["cpu"] = newCPU
// 触发原地扩缩
return q.kubeClient.Pods(job.Namespace).UpdateResources(context.TODO(), podSpec)
}
1.6 拓扑感知工作负载调度(Topology-Aware Workload Scheduling)
v1.36 还引入了拓扑感知的 PodGroup 调度。你可以用拓扑标签(如 topology.kubernetes.io/rack)将一组 Pod 约束在同一个物理域内:
apiVersion: scheduling.sigs.k8s.io/v1alpha1
kind: PodGroup
metadata:
name: distributed-training-pg
spec:
topologySpreadPolicy:
topologyKey: topology.kubernetes.io/rack
minMembers: 8
这对 AI 训练特别重要——如果你把分布式训练的 8 个 Pod 分散到不同机架,网络延迟会严重影响 AllReduce 的效率,导致 GPU 利用率低下。拓扑感知调度确保它们落在同一机架或同一可用区,减少跨网络通信开销。
二、安全:从"可选加固"到"默认安全"
2.1 用户命名空间(User Namespaces):GA 了
这是 v1.36 最具里程碑意义的安全功能:User Namespaces 正式达到 GA(General Availability)。
核心机制:将容器内的 root 用户映射为主机上的非特权 UID/GID。
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true
containers:
- name: app
image: nginx:latest
securityContext:
runAsUser: 0 # 容器内是 root
# 但在主机上,这个 root 映射为普通用户 UID 100000
映射关系在 /etc/subuid 和 /etc/subgid 中定义:
# /etc/subuid(宿主机)
user:100000:65536 # 用户 user 的子 UID 范围:100000 ~ 165535
安全效果:
- 即使容器内进程通过漏洞拿到了 root 权限,它在宿主机上也只是普通用户 UID 100000
- 无法直接修改系统关键文件、无法挂载敏感路径、无法修改内核参数
- 这是容器逃逸的"最后一道防线"
Kubernetes 官方博客的表述:"即使进程突破容器隔离,也无法获取底层节点的管理权限。"
2.2 Mutating Admission Policies:Webhook 的原生替代
MutatingAdmissionPolicies 在 v1.36 GA,它允许用 CEL(Common Expression Language)直接在 API Server 内执行资源变更逻辑,无需额外部署 Webhook:
# 传统做法:需要一个独立 Webhook 服务器
# v1.36 新做法:直接用声明式策略
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: MutatingAdmissionPolicy
metadata:
name: inject-sidecar-policy
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
operations: ["CREATE"]
patchTypes: ["JSONPatch"]
CEL:
expression: >
object.spec.containers.exists(c, c.name == "envoy")
? object
: object.with({
spec: object.spec.with({
initContainers: [{
name: "proxy-init",
image: "istio/proxyv2:1.20",
securityContext: { runAsNonRoot: true }
}]
})
})
传统 MutatingWebhook 的问题:
- 需要额外部署一个服务,消耗计算资源
- 每次 API 请求都需要网络跳转(latency 增加)
- 需要维护证书、域名、HA 等运维复杂度
CEL 表达式的优势:
- 原生集成在 API Server 内,无网络开销
- 声明式版本化管理,随 Git 走
- 不存在服务可用性问题
2.3 细粒度 Kubelet API 授权:GA
在 v1.36 之前,监控工具要获取节点级别的指标,需要申请 nodes/proxy 权限——这个权限本质上是授予了所有节点代理端点的访问权,范围太宽。
v1.36 GA 的细粒度 Kubelet API 授权支持对 HTTPS API 做最小权限拆分:
// 旧做法:权限过大
{
"apiGroups": [""],
"resources": ["nodes/proxy"],
"verbs": ["get", "create"]
}
// v1.36 新做法:精确到节点级别
{
"apiGroups": [""],
"resources": ["nodes/metrics", "nodes/spec", "nodes/logs"],
"resourceNames": ["node-1", "node-2"],
"verbs": ["get"]
}
2.4 AppArmor:第一类 API 支持
v1.36 正式移除了旧版 AppArmor 注解(container.apparmor.security.beta.kubernetes.io/),全面迁移到正式的 appArmorProfile 字段:
apiVersion: v1
kind: Pod
spec:
containers:
- name: web
image: nginx
securityContext:
appArmorProfile:
type: RuntimeDefault # 使用容器运行时的默认 AppArmor profile
这是从"hacky metadata"到"first-class API"的转变,AppArmor 配置正式成为 Pod Spec 的一部分,与 seccomp、SELinux 等安全机制平起平坐。
2.5 已移除的危险功能
本次版本也移除了两个有安全风险的功能:
gitRepo 卷插件:自 v1.11 开始废弃,现已彻底移除。它曾允许攻击者以 root 权限在宿主机执行代码。替代方案是使用 Init Container + git-sync 工具。
Kube-proxy IPVS 模式:自 v1.35 废弃后移除。
三、存储与 CSI:企业级存储能力的补完
3.1 卷组快照(Volume Group Snapshots):GA
经过多个版本的 Beta 打磨终于 GA。这个功能允许同时对多个 PVC 创建崩溃一致性快照:
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeGroupSnapshot
metadata:
name: db-snapshot
namespace: database
spec:
source:
persistentVolumeClaimName: postgres-data
volumeGroupSnapshotClassName: csi-aws-vsc
status:
creationTime: "2026-04-22T08:00:00Z"
readyToUse: true
volumeGroupSnapshotHandle: aws-snap-xxx
应用场景:
- 数据库的一致性备份(同时快照 WAL 卷 + 数据卷)
- 有状态应用的跨区域灾难恢复
- 蓝绿部署前的状态保存
3.2 可变 CSI 卷附加限制
CSI 驱动现在可以动态更新节点能处理的最大卷数量,Kubelet 无需重启即可感知变化:
# CSI 驱动在运行时更新节点容量
# kubelet 定期轮询并更新 CSINode.spec allocatable
apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
name: node-1
spec:
drivers:
- name: pd.csi.storage.gke.io
nodeID: node-1
allocatable:
count: 16 # 动态更新,无需重启 kubelet
volumeHandles:
- pd-xxx
这解决了云环境中的一个老大难问题:节点启动时分配的卷配额往往是静态的,但在 GKE/EKS 等托管集群中,节点扩缩容事件频繁发生,卷配额需要实时更新。
四、API 可扩展性与规模化
4.1 分片列表与分片监听流(Alpha)
拥有大量 Controller 的大型集群,常遇到 Watch 流瓶颈:所有观察者都通过单一连接接收同一种资源的更新,在超大规模部署中形成性能瓶颈。
v1.36 引入分片机制——将监听流分摊到多个连接:
// 伪代码:分片监听流的客户端使用方式
client := clientset.NewForConfig(config)
// 旧做法:单一流
watcher, _ := client.CoreV1().Pods("").Watch(context.TODO(), metav1.ListOptions{})
// v1.36 新做法:分片监听(提高大规模集群的响应性)
shardedWatcher, _ := client.NewShardedWatch(context.TODO(),
ShardedWatchOptions{
Resource: "pods",
ShardCount: 4, // 4 个分片并行接收更新
})
Palark 团队的评价:"解决了超大规模部署里监听流容易成为性能瓶颈的关键痛点。"
4.2 外部服务账号 Token 签名:GA
企业有现有的 IAM 系统(比如 Vault、AWS IAM),不希望 Kubernetes 控制面自己管理签名密钥。v1.36 GA 后,API Server 可以将 Token 签名职责委托给外部系统:
# API Server 配置:将 Token 签名委托给外部 signer
apiVersion: apiserver.config.k8s.io/v1
kind: AuthenticationConfiguration
serviceAccountTokenSigner:
external:
issuer: https://auth.company.com
jwks:
url: https://auth.company.com/.well-known/jwks.json
# API Server 自动缓存公钥,验证它自己没签发的 Token
4.3 gogoprotobuf 依赖移除
v1.36 完成了对未维护的 gogoprotobuf 依赖的彻底清除。这不仅是安全清理,也消除了升级 Go 版本时的阻塞障碍——gogoprotobuf 与新版本 Go 不兼容,阻止了 Kubernetes 升级编译器。
五、生产运维:值得关注的变化
5.1 Pod 资源健康状态(Beta)
现在 Kubelet 会报告分配给 Pod 的设备(GPU/DRA 设备)的健康状态:
# kubectl describe pod 可以直接看到设备状态
$ kubectl describe pod distributed-training-0
...
Allocated Resources:
Resource Requests Limits
nvidia.com/gpu 1 1
Memory 32Gi (85%) 64Gi (42%)
Container Status:
...
Allocated Resources Status:
nvidia.com/gpu:
Health: Unhealthy # 设备故障,直接可见!
Reason: NVLinkError
Message: "GPU 3 NVLink connection degraded"
这解决了 AI 运维中的一个大痛点:当 Pod 因为硬件故障 crash 时,你不需要登录到节点去查 dmesg,直接 kubectl describe pod 就知道是不是 GPU 坏了。
5.2 节点日志查询:GA
以前查 kubelet 日志需要 SSH 登录节点,v1.36 GA 后直接用 kubectl:
# 查询 kubelet 日志(无需 SSH)
kubectl debug node/node-1 -it --image=busybox -- cat /var/log/kubelet.log
# 跨节点的日志聚合查询(Alpha)
kubectl logs --all-nodes --since=1h --selector app=nginx
5.3 cgroup v2 内存服务质量(Beta)
进入 Beta 的 Memory QoS 功能提供分层内存保护:
- 内存保证(memory.min):低于此值,内核不会回收该 Pod 的内存
- 内存软限制(memory.low):低于此值,内核优先回收而非节流
- 内存高压(memory.high):超过此值,内核对该 Pod 进行 throttling
apiVersion: v1
kind: Pod
spec:
containers:
- name: latency-sensitive
resources:
requests:
memory: "4Gi"
limits:
memory: "8Gi"
# v1.36 Beta: cgroup v2 内存 QoS 自动生效
# memory.min = requests.memory(保证不回收)
# memory.high = limits.memory * 0.95(接近限制时 throttling)
5.4 OCI 镜像作为卷源(GA)
现在可以直接用 OCI Registry 里的镜像作为数据卷:
apiVersion: v1
kind: Pod
spec:
containers:
- name: ml-inference
image: model-server:v1.0
volumeMounts:
- name: model
mountPath: /models
volumes:
- name: model
ocImage:
reference: registry.company.com/models/llama3-8b:1.0
pullSecrets:
- name: registry-secret
这对于 AI 推理场景特别有用:模型文件作为只读数据,通过 OCI 镜像版本化管理,配合签名验证确保完整性。
5.5 弃用清单:升级前必读
| 被移除功能 | 替代方案 |
|---|---|
| gitRepo 卷插件 | Init Container + git-sync |
| Kube-proxy IPVS 模式 | iptables/nftables |
| FlexVolume(kubeadm) | CSI |
| AppArmor 旧注解 | appArmorProfile 字段 |
| Ingress NGINX 项目 | 2026年3月24日正式退役 |
Ingress NGINX 退役是大事。这是过去在 Kubernetes 中最广泛使用的 Ingress 实现。官方建议迁移到 Gateway API(networking.k8s.io/gateway)。如果你还在用 Ingress NGINX,现在是时候行动了。
六、开发者体验:从"能用"到"好用"
6.1 CEL 验证生成器(validation-gen GA)
以前为 CustomResourceDefinition 写验证逻辑,需要手动维护 OpenAPI Schema,很容易出现 Schema 与代码不同步的 bug。
v1.36 GA 后,开发者可以直接在 Go 类型定义里加注解:
// types.go
type ClusterConfig struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ClusterConfigSpec `json:"spec"`
}
type ClusterConfigSpec struct {
// +k8s:validation:minimum=1
// +k8s:validation:maximum=100
Replicas int32 `json:"replicas"`
// +k8s:validation:enum=small;medium;large
Size string `json:"size"`
// +k8s:validation:pattern=^[a-z][a-z0-9-]*$
ClusterName string `json:"clusterName"`
}
validation-gen 工具读取这些注解,自动生成对应的验证代码,与类型定义始终保持同步。
6.2 失效率缓解(Staleness Mitigation)
Controller 的"状态过时"问题长期以来是 Kubernetes 内部的隐患:当 Controller 的本地缓存与实际集群状态不同步时,Controller 可能会基于错误状态做出错误决策(如双重更新导致数据损坏)。
v1.36 引入的新机制让 Controller 能够感知自身的状态陈旧度,并推迟协调直到状态同步:
// 伪代码:失效率感知的 Controller 协调逻辑
func (c *Controller) reconcile(key string) error {
// 检查本地缓存是否过时
if c.cache.IsStale() {
// 等待缓存同步完成后再处理
return c.waitForCacheSync()
}
// 正常协调逻辑
obj, err := c.getObject(key)
return c.processObject(obj)
}
七、升级指南:v1.36 升级检查清单
如果你当前运行的是 v1.34/v1.35,升级到 v1.36 之前需要做以下检查:
必做项
- 审计 gitRepo 卷使用:搜索集群中所有使用
gitRepo卷的 Pod,制定迁移到 Init Container 的计划 - Ingress NGINX 评估:如果使用 Ingress NGINX,评估 Gateway API 迁移方案
- 检查 AppArmor 注解:将
container.apparmor.security.beta.kubernetes.io/迁移到正式字段 - 确认 cgroup v2:Memory QoS Beta 依赖 cgroup v2,确保节点使用 cgroup v2(大多数现代 Linux 发行版已默认使用)
推荐项
- 启用 User Namespaces:对于跑非信任工作负载的 Pod,启用用户命名空间隔离
- 测试 MutatingAdmissionPolicies:评估是否可以用 CEL 策略替代现有的 MutatingWebhook
- 开启 Pod 资源健康状态:为 GPU Pod 配置健康检查,验证监控能力
API 变更提醒
scheduling.k8s.io/v1alpha1的 PodGroup API 进入 Beta(需要相应 RBAC 权限)resource.k8s.io/v1alpha1的 ResourcePoolStatusRequest API 引入新字段
八、深度总结:Kubernetes 的成人礼意味着什么
从 v1.36 的变化中,我们可以看到 Kubernetes 正在发生三个根本性转变:
转变一:从"灵活的容器调度器"到"AI 基础设施控制面"
过去 Kubernetes 的核心价值是"用声明式的方式跑容器"。但 v1.36 告诉我们,Kubernetes 的设计目标已经扩展到了 GPU 集群管理、分布式训练编排、AI 加速器的资源抽象。
这不是一个附加功能,而是架构层面的深度整合——DRA 的完善、PodGroup 原子调度、原地资源扩缩容,这些功能的组合意味着:在 Kubernetes 上跑 AI 训练任务,终于可以不需要额外的自定义调度层了。
转变二:从"配置即责任"到"默认安全"
Kubernetes 长久以来被人诟病"默认不安全"——跑一个默认配置的集群,攻击面非常大。User Namespaces GA、MutatingAdmissionPolicies GA、AppArmor 第一类支持,这些变化的共同方向是:把安全最佳实践内置到平台里,而不是留给运维人员去配置。
这呼应了 VMware 的判断:"Kubernetes 正从一个灵活的框架逐步转向拥有更标准化、更具强制性的默认安全与资源规范。"
转变三:从"部署工具"到"持续运营平台"
Ingress NGINX 的退役、gogoprotobuf 的清理、IPI/CIDR 严格验证……这些变化加起来,意味着 Kubernetes 在快速迭代的同时,也在加速"断舍离"——把遗留问题、危险设计、不可维护的代码尽快清出主干。
对企业来说,这意味着:升级 Kubernetes 版本不再是一个可以无限推迟的运维任务。版本迭代速度加快,平台团队需要建立更系统化的升级流程和测试体系。
附录:关键资源
| 资源 | 链接 |
|---|---|
| 官方发布博客 | kubernetes.io/blog/2026/04/22/kubernetes-v1-36-release/ |
| GitHub CHANGELOG | github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.36.md |
| KEP 合集 | kep.k8s.io(搜索 1.36 相关 KEP) |
| Palark v1.36 深度分析 | palark.com/blog/kubernetes-1-36-release-features/ |
| VMware 企业视角 | blogs.vmware.com/cloud-foundation/2026/04/29/kubernetes-1-36-what-actually-changed-for-enterprise-platforms/ |
本文涵盖 Kubernetes v1.36 代号 Haru 的 70 项增强中最重要的架构性变化。完整变更清单请参考官方 CHANGELOG。