Kubernetes 1.36 深度拆解:当云原生控制平面进入「资源感知」时代——从 DRA 设备污点与优先列表到调度器并行 PreBind、从原地垂直缩容到 Ingress NGINX 退役的工程全貌(2026)
2026 年 4 月底,Kubernetes 1.36 悄然落地。它没有像 1.30 那样高举「结构化参数 DRA」的旗帜,也没有像 1.24 那样干掉 Dockershim 般惊天动地,但它做了一件更底层、也更深远的事:把「资源」正式变成了调度的一等公民。
如果说过去十年的 Kubernetes 解决的是「如何把无状态服务跑起来」,那么 1.36 标志着它开始认真回答下一个十年最关键的问题:如何把 GPU、FPGA、DPU、NPU 这些昂贵且稀缺的异构硬件,像调度 CPU 与内存一样精细、可组合、可约束地调度起来。
本文从工程视角,带你看懂 1.36 这条「资源感知」主线背后的架构演进、代码实战与生产级升级陷阱。
一、背景:为什么 1.36 是「资源感知」的拐点
要理解 1.36 为什么重要,得先回到一个被忽视已久的事实:Kubernetes 的资源模型,从 1.0 到 1.35,本质上只认两种东西——CPU 和内存。
扩展资源(Extended Resources)机制让我们可以 kubectl describe node 看到 nvidia.com/gpu: 8,但它有三个结构性缺陷:
- 不透明:GPU 对你来说只是一个整数,调度器不知道它是 A100 还是 H100,不知道它的显存、NVLink 拓扑、是否健康。
- 不可分:你没法要「半个 GPU」或「一张卡上的 40GB 显存」,整数资源要么全给要么不给。
- 无拓扑:多卡训练时,NUMA 亲和、PCIe Switch 归属、跨节点 NVLink 这些决定训练带宽的关键信息,调度器一无所知。
这直接导致了一个行业怪象:在大模型时代,真正稀缺的 GPU 调度,长期靠 Volcano、YuniKorn 这类外部调度器 或者 各云厂商自研的 Device Plugin + 自定义 Webhook 来补位。Kubernetes 原生的调度器,在面对 AI 工作负载时,居然是个「残血版」。
DRA(Dynamic Resource Allocation,动态资源分配)就是为此而生的。它的目标很简单:让任意硬件资源,都能用和 CPU/内存同源的、声明式的、拓扑感知的方式被申请、调度、分配和回收。
DRA 在 1.26 以 Alpha 登场,1.30 引入「结构化参数(Structured Parameters)」彻底重写了设备建模方式,1.32 进入 Beta。而 1.36,是 DRA 第一次以「多子特性 GA + 多子特性 Beta 默认启用」的姿态,真正 ready for production 的版本。
这也是为什么本文把 1.36 定义为「资源感知」拐点:它不只是加了一个特性,而是把整个控制平面的调度哲学,从「Pod 级、CPU/内存导向」推向了「Workload 级、异构硬件导向」。
除了 DRA,1.36 还顺手干了三件大事,构成本文的主线:
- 调度器范式转移:引入 Workload/PodGroup API,支持 Gang Scheduling、拓扑感知调度(TAS)、整组抢占。
- 原地垂直伸缩 GA 化:
InPlacePodVerticalScaling进入 Beta 且默认启用,Pod 不用重建就能改 CPU/内存。 - Ingress NGINX 正式退役:2026-03-24 官方宣布停止维护,标志着 Ingress API 的黄昏与 Gateway API 的黎明。
二、核心概念:重新理解 1.36 的资源模型
2.1 DRA 到底是什么,为什么 Device Plugin 不够用
先把结论说清楚:DRA 不是 Device Plugin 的升级版,而是它的替代品思路。两者走的是完全不同的路线。
Device Plugin 的模型是「节点侧上报整数 → 调度器当整数用」:
GPU 节点 kubelet
└─ device-plugin(每类硬件一个守护进程)
└─ 向 kubelet 注册:nvidia.com/gpu = 8
└─ kubelet 把 8 写进 Node.status.allocatable
└─ 调度器只知道「有 8 个不透明的 GPU」
DRA 的模型是「驱动侧声明结构化设备 → 调度器做结构化匹配 → 分配后绑定 Claim」:
DRA 驱动(如 gpu-dra-driver)
└─ 发布 ResourceSlice:描述本节点有哪些 Device、每个 Device 的属性/容量/拓扑/污点
└─ 用户创建 ResourceClaimTemplate:声明「我要一张 H100、显存≥80G、与某 NUMA 亲和」
└─ Pod 引用该 ClaimTemplate
└─ 调度器读取 ResourceSlice,按属性做结构化匹配,选出最优 Device
└─ ResourceClaim 绑定到具体 Device,kubelet 拿到结果准备容器
注意这个模型的关键差异:匹配发生在调度器里,且是基于结构化属性(attributes/capacity/topology)的匹配,而不是基于整数扣减。这带来的能力飞跃包括:
- 部分分配(Partitionable):一张 80GB 显存的卡,可以分给两个 Pod 各 40GB。
- 属性匹配:可以声明「要 A100 80GB 且 topology.kubernetes.io/nodenum=0」。
- 设备故障隔离:单个 Device 不健康,只影响它自己,不影响整节点。
1.36 中 DRA 各子能力的成熟度矩阵如下(这是本文最该记住的一张表):
| 子特性 | 状态 | 默认启用 | 工程含义 |
|---|---|---|---|
| DRA 扩展资源(Extended Resources) | Beta | 否 | 支持扩展资源类型接入 DRA |
| DRA 设备绑定条件(Device Binding Conditions) | Beta | 是 | Device 分配后有结构化状态条件,可观测 |
| DRA 设备污点与容忍(Device Taints & Tolerations) | Beta | 否 | Device 可打污点,Pod 需容忍才能用,类似节点污点 |
| DRA 可消费容量(Consumable Capacity) | GA | 是 | 支持可分区设备的容量管理(如一张卡分显存) |
| DRA 分区设备(Partitionable Devices) | Beta | 否 | 设备可物理/逻辑分区 |
| DRA 优先列表(Priority List) | GA | 是 | 设备选择支持优先列表,调度器按偏好排序 |
| DRA 管理员访问(Admin Access) | GA | 是 | 管理员可直接访问/调试设备 |
| DRA 原生资源映射(Native Resource Mapping) | Alpha | 否 | 把设备算力折算进 CPU/内存预算(见 2.4) |
| DRA 列表类型属性(List-type Attributes) | Alpha | 否 | Device 属性支持列表类型 |
这张表读下来,信号非常明确:「可消费容量 + 优先列表 + 设备绑定条件」三项 GA/默认启用,意味着 1.36 已经可以安全地拿 DRA 跑生产级的 GPU 共享与偏好调度了。
2.2 调度器范式转移:从 Pod 级到 Workload 级
DRA 解决的是「单类硬件怎么精细分配」,而 Workload/PodGroup API 解决的是「一组 Pod 怎么作为一个整体被调度」。
在 1.36 之前,要做 Gang Scheduling(要么全有要么全无的组调度),基本只能上 Volcano 或 YuniKorn。1.36 把这件事往原生拉近了一大步:引入 scheduling.k8s.io/v1alpha2 的 Workload 和 PodGroup API。
它的价值在哪?以分布式训练为例:一个 8 Pod 的 PyTorch Job,如果只调度了 3 个 Pod 就资源不足了,那 3 个 Pod 占着 GPU 却跑不起来,造成资源死锁。Gang Scheduling 保证「凑不齐 8 个就一个都别跑」,避免这种碎片僵局。
1.36 在调度器侧配套了三件套:
- 拓扑感知工作负载调度(TAS, Topology Aware Scheduling):Alpha,支持基于拓扑域(NUMA / 机架 / 可用区)的 PodGroup 调度,让一组 Pod 尽量落在低延迟拓扑域内。
- 工作负载感知抢占(Workload-aware Preemption):不再抢单个 Pod,而是抢「整个 PodGroup」,避免抢了一半导致 Gang 永远不满足。
- PodGroupPodsCount 插件:放置决策时,优先选择「同组 Pod 数量更多」的位置,提升局部性。
配套地,调度器内部把 PodGroupInfo 重命名为 PodGroupState——如果你写了自定义调度器插件,这是 1.36 必须改的接口名之一(详见第五章)。
2.3 原地垂直伸缩:InPlacePodVerticalScaling 进入 Beta 默认启用
这是一个被 DRA 光芒掩盖、但对普通业务极其实用的特性。
过去要改一个 Pod 的 CPU/内存,唯一正统做法是用 VPA 的 Recreate 模式——删掉 Pod 重建。这意味着哪怕你只是想把内存上限从 512Mi 调到 1Gi,也得经历一次服务中断(除非你有多副本 + 滚动)。
InPlacePodVerticalScaling 让你不重建 Pod,直接热改运行中容器的 resources:
- 支持 Pod 级 CPU/内存原地调整;
- 支持非 sidecar 的 initContainer 原地调整;
- 关键改进:当调整后的请求超过节点可分配容量时,在准入阶段就直接拒绝,而不是标记为
Infeasible让 Pod 卡在那里。
它的实现机制是:kubelet 调用 CRI 的 UpdateContainerResources 直接改 cgroup,再更新 Pod 的 status.resize。这背后是对 resources 字段做「当前值 vs 目标值」的 diff,并通过 resizePolicy 决定每个资源是否允许不重启(NotRequired)还是必须重启(RestartContainer)。
2.4 准入与安全的 GA 化
1.36 把一批安全相关特性推到了 GA,值得平台团队重点关注:
- MutatingAdmissionPolicy(GA):用 CEL 表达式替代 Webhook 做简单变更(如自动打 label),延迟从 Webhook 的几十毫秒降到近乎零。这是「去 Webhook 化」的重要一步。
- UserNamespacesSupport(GA):Pod 可以以非 root 的 user namespace 运行,即使容器内写死 uid 0,在宿主机也映射成普通 uid,大幅降低容器逃逸危害。
- SELinuxChangePolicy & SELinuxMountReadWriteOncePod(GA):更细的 SELinux 标签策略与卷挂载控制。
- ConstrainedImpersonation / NodeDeclaredFeatures / ExternalServiceAccountTokenSigner / CSIServiceAccountTokenSecrets:分别收紧了「模拟他人」的权限边界、节点特性声明、SA Token 外部签名、CSI 的 SA Token Secret 管理。
三、架构分析:DRA 与调度器如何协同
理解一个特性最好的方式,是顺着一次请求看它如何流经控制平面。下面以「申请一张带污点容忍与优先列表的 GPU」为例,拆解 1.36 的 DRA 全链路。
3.1 DRA 全链路数据流
┌─────────────┐ ResourceSlice ┌──────────────────┐
│ gpu-dra-driver│ ────(节点侧)─────▶│ API Server │
│ (DaemonSet) │ │ resource.k8s.io │
└─────────────┘ │ /resourceclaims │
│ /resourceslices │
┌─────────────┐ ResourceClaim └────────┬─────────┘
│ 用户 YAML │ ───(创建)───────────────────┘
│ (ClaimTmpl) │ │ 调度器 Watch
└─────────────┘ ▼
┌─────────────┐ ┌──────────────────┐
│ scheduler │ ◀── 读取 ResourceSlice ──│ 结构化匹配算法 │
│ (DRA 插件) │ │ (属性/容量/拓扑/ │
│ │ ── 选出 Device ───▶│ 污点/优先列表) │
└──────┬──────┘ └──────────────────┘
│ 绑定 ResourceClaim → Device
▼
┌─────────────┐ Pod 调度到节点 ┌──────────────────┐
│ kubelet │ ◀── Claim 已绑定 ──│ DRA 驱动 Prepare │
│ (DRA 分配) │ │ (分配显存/设备) │
└──────┬──────┘ └──────────────────┘
│ 注入设备信息到容器 env / device
▼
容器拿到具体 GPU(如 /dev/nvidia0,40GB 显存)
关键点在于:调度器在决策 Pod 落在哪个节点之前,就已经知道每台机器上每个 Device 的结构化属性。它做的不是「整数扣减」,而是一次「带约束的最优化」——这也是 1.36 优先列表(Priority List)GA 的意义:当有多个满足条件的 Device 时,调度器按你的优先级偏好(比如「优先同 NUMA 域」「优先空闲显存多」)排序选优。
1.36 还修了一个生产级 Bug:DRA 调度竞争——在快速调度时,同一设备可能被重复分配给两个 Claim。修复后,分配有了更强的互斥保证。
3.2 调度器内部:PreBind 并行化
这是 1.36 调度器最容易被忽略、但对大规模集群延迟影响最大的改动。
调度框架的 PreBind 阶段,过去是串行执行的:所有 PreBind 插件排着队,一个个跑完才能提交绑定。当集群里有多个重量级 PreBind 插件(卷预挂载、设备准备、网络预配置),串行就成了调度延迟的瓶颈。
1.36 引入 PreBindPreFlight:插件通过它声明「我是否支持并行」。返回 AllowParallel: true 的插件,会被调度器并发执行 PreBind。
旧:PreBind A → PreBind B → PreBind C → Bind (串行,总耗时 A+B+C)
新:PreBind A ┐
PreBind B ├─ 并行 → Bind (并行,总耗时 max(A,B,C))
PreBind C ┘
代价是:并行插件必须保证自己的 PreBind 操作是幂等且无跨节点副作用的,否则并发会引入竞态。这正是为什么 1.36 用「显式声明 AllowParallel」而非「默认并行」——把安全判断交给插件作者。
同理,PostFilterResult 被扩展:自定义抢占插件现在必须返回被抢占的 Pod 列表,供工作负载感知抢占(整组抢占)使用。
3.3 kube-controller-manager 中的 DRA 控制器
DRA 背后有两个关键控制器:
- ResourceClaim 控制器:监听 Claim 的分配请求,驱动 DRA 驱动完成分配/去分配;1.36 强化了分配状态条件(Device Binding Conditions)。
- ResourceSlice 控制器:管理驱动上报的 Slice 生命周期。1.36 一个重要变更:发布集群范围(cluster-scoped)资源时,必须显式设置
ReconcilePoolWithName,「All nodes」不再是默认值。如果你的 DRA 驱动依赖旧行为,升级后会不再自动协调所有节点——这是升级必查项。
四、代码实战
光讲概念太空,下面上可运行的真实配置与代码。
4.1 DRA 实战:声明一张带设备污点容忍与优先列表的 GPU
假设集群里跑着一个 GPU DRA 驱动,它会为每个 GPU 发布一个 ResourceSlice。我们先看驱动侧如何描述设备(含拓扑、属性、容量、污点):
# ResourceSlice:由 gpu-dra-driver 自动发布,这里展示其结构
apiVersion: resource.k8s.io/v1beta1
kind: ResourceSlice
metadata:
name: gpu-node-1-slice
labels:
resource.kubernetes.io/managed-by: gpu-dra-driver
spec:
driver: gpu.example.com
pool:
name: node-1-pool
resourceGroupName: gpus
# 该节点上的设备列表(结构化)
devices:
- name: gpu-0
# 设备属性,调度器据此做结构化匹配
attributes:
- name: model
value:
string: "H100"
- name: arch
value:
string: "hopper"
# 可消费容量:80GB 显存可被分区分配
capacity:
- name: memory
value:
quantity: "80Gi"
# 拓扑:归属 NUMA 域 0,调度器据此做拓扑感知
topology:
nodes:
- name: node-1
attributes:
- name: kubernetes.io/nodenum
value:
int: 0
# 1.36 新增:设备污点——需 Pod 容忍才能使用
taints:
- key: gpu.example.com/reserved
value: "team-a"
effect: NoSchedule
- name: gpu-1
attributes:
- name: model
value:
string: "A100"
capacity:
- name: memory
value:
quantity: "40Gi"
用户侧,通过 ResourceClaimTemplate 声明需求,并引用优先列表与污点容忍:
# ResourceClaimTemplate:声明「我要 H100、显存可消费、容忍 reserved 污点」
apiVersion: resource.k8s.io/v1beta1
kind: ResourceClaimTemplate
metadata:
name: h100-claim-template
spec:
spec:
devices:
requests:
- name: gpu
deviceClassName: gpu-h100
# 1.36 新增:优先列表,调度器按偏好排序选 Device
prioritization:
- attribute: memory # 优先显存大的
sort: Descending
- attribute: kubernetes.io/nodenum
sort: Ascending # 其次优先 NUMA 0
# 1.36 新增:对设备污点的容忍
tolerations:
- key: gpu.example.com/reserved
operator: Equal
value: "team-a"
effect: NoSchedule
---
# Pod 引用上面的 ClaimTemplate
apiVersion: v1
kind: Pod
metadata:
name: train-job
spec:
resourceClaims:
- name: gpu
resourceClaimTemplateName: h100-claim-template
containers:
- name: trainer
image: pytorch:2.5
command: ["python", "train.py"]
注意 prioritization 与 tolerations 是 1.36 DRA 的核心新增。前者让调度器在「多个满足条件的 Device」之间做有偏好的选择(GA),后者让设备能像节点一样打污点做隔离(Beta)。这就是「资源感知调度」从 PPT 走进 YAML 的真实形态。
4.2 原生资源映射(Alpha):把设备算力折算进预算
1.36 还有一个 Alpha 特性 Native Resource Mapping:允许把设备的算力,映射成调度器原生理解的 CPU/内存预算。
场景:某 DPU 卡在转发时会占用节点的部分 CPU。通过原生资源映射,驱动可以声明「这张 DPU 消耗 2 核 CPU + 4Gi 内存」,调度器在排 Pod 时会把这 2 核从节点可分配里扣掉——设备资源与 CPU/内存第一次在同一个预算池里统一核算。对异构硬件密集的节点,这能避免「GPU 用着、CPU 却被 DPU 偷偷吃满」的隐性超卖。由于是 Alpha,生产谨慎开启,但方向极其重要。
4.3 自定义调度器插件:实现并行 PreBind
下面是一段真实的自定义调度器插件骨架,演示 1.36 的 PreBindPreFlight 并行声明:
package parallelprebind
import (
"context"
"fmt"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
framework "k8s.io/kubernetes/pkg/scheduler/framework"
)
// ParallelPreBind 是一个支持并行 PreBind 的自定义插件
type ParallelPreBind struct{}
func (pl *ParallelPreBind) Name() string { return "ParallelPreBind" }
// PreBindPreFlight 是 1.36 新增的方法:声明本插件是否可并行执行 PreBind。
// 返回 AllowParallel: true 后,调度器会并发执行本插件的 PreBind,
// 前提是你的 PreBind 操作幂等且无跨节点副作用。
func (pl *ParallelPreBind) PreBindPreFlight(
_ context.Context,
_ *framework.CycleState,
pod *v1.Pod,
) (*framework.PreBindPreFlightResult, error) {
return &framework.PreBindPreFlightResult{
AllowParallel: true,
}, nil
}
// PreBind 实际执行绑定前的准备(例如幂等的卷预挂载、写 annotation)。
// 因为 PreBindPreFlight 声明了 AllowParallel,本方法可能与其他 PreBind 并发执行。
func (pl *ParallelPreBind) PreBind(
_ context.Context,
_ *framework.CycleState,
pod *v1.Pod,
nodeName string,
) *framework.Status {
// 必须是幂等操作:多次执行结果一致,且不依赖其他节点的状态
fmt.Printf("[ParallelPreBind] preparing pod %s/%s on node %s\n",
pod.Namespace, pod.Name, nodeName)
return framework.NewStatus(framework.Success)
}
// 注册插件(省略 New 与插件工厂代码,实际需实现 framework.PluginFactory 注册)
var _ framework.PreBindPlugin = &ParallelPreBind{}
几个写插件时必须注意的 1.36 接口变更:
- 必须实现
PreBindPreFlight,否则调度器按「旧串行语义」处理(返回nil即保持串行)。 PostFilter现在要求返回PostFilterResult且包含被抢占的 Pod 列表,否则编译/运行报错。PodGroupInfo已重命名为PodGroupState,引用旧名的插件需全局替换。
4.4 原地垂直伸缩:给运行中的 Pod 热改资源
InPlacePodVerticalScaling 在 1.36 默认启用。下面演示不重启 Pod 改资源:
# 原始 Pod,声明 resizePolicy 允许 CPU/内存不重启调整
apiVersion: v1
kind: Pod
metadata:
name: resize-demo
spec:
containers:
- name: app
image: nginx:1.27
resizePolicy: # 1.36 推荐显式声明
- resource: cpu
restartPolicy: NotRequired # 改 CPU 不重启容器
- resource: memory
restartPolicy: NotRequired # 改内存不重启容器
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
运行中热改(kubectl 直接 patch 子资源 resize):
kubectl patch pod/resize-demo --subresource resize --patch '{
"spec": {
"containers": [{
"name": "app",
"resources": {
"requests": {"cpu": "500m", "memory": "512Mi"},
"limits": {"cpu": "1", "memory": "1Gi"}
}
}]
}
}'
1.36 的体验改进在于:如果新请求超过节点 allocatable,准入阶段直接拒绝,而非让 Pod 进入 Infeasible 永久挂起。你可以用 kubectl get pod resize-demo -o jsonpath='{.status.resize}' 观察分配进度(Proposed → InProgress → Infeasible/Proposed)。
4.5 MutatingAdmissionPolicy:用 CEL 替代简单 Webhook
过去给所有 Pod 自动打 cost-center 标签,要写一个 Mutating Webhook(Deployment + Service + 证书 + 代码)。1.36 的 MutatingAdmissionPolicy(GA)用 CEL 一行表达式搞定:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: add-cost-center
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
# CEL 表达式:若 Pod 还没 cost-center 标签,则补一个默认值
mutations:
- patchType: ApplyConfiguration
applyConfiguration:
expression: |
object.spec.?metadata.?labels.orValue({})
.costCenter == "" ?
object : object
---
# 绑定:决定哪些 Pod 受此策略约束
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicyBinding
metadata:
name: add-cost-center-binding
spec:
policyName: add-cost-center
matchResources:
namespaceSelector:
matchLabels:
mutate: enabled
这把「简单标签注入、字段默认值」这类高频但低风险的变更,从 Webhook 的「网络往返 + 证书管理」降级为「API Server 内 CEL 求值」。延迟与运维成本双降,是 1.36 平台工程收益最直观的甜点特性。
五、性能优化与运维
5.1 调度器 PreBind 并行化的吞吐收益
如果你的自定义调度器中 PreBind 插件较多(卷、设备、网络、配额),1.36 的并行化能直接把「单 Pod 调度延迟」从「各 PreBind 之和」降到「最慢一个」。在单机每秒数百 Pod 调度的场景,这意味着可观测的尾延迟(p99)下降。但要注意:并行插件必须幂等,且避免共享可变状态。
5.2 kube-proxy 的 conntrack 清理与 nftables 兼容
1.36 优化了 kube-proxy 的 conntrack 清理逻辑:在存在大量过期连接时,清理性能大幅提升(避免旧版本里 O(n) 扫描卡顿)。同时 nftables 模式修复了对 nft 1.1.3 的兼容性——如果你在用 nftables 模式 kube-proxy,升级后建议验证 iptables-nft/nft 版本匹配,否则可能出现规则加载异常。
5.3 可观测性增强:PSI、NodeLogQuery、Native Histograms
- KubeletPSI(GA):Linux PSI(Pressure Stall Information)指标默认暴露 CPU/内存/IO 压力,比单纯看 CPU 利用率更能提前发现「资源争抢导致卡顿」。
- NodeLogQuery(GA):可直接查询节点上容器/系统日志,排障不必再
kubectl exec进节点。 - Prometheus Native Histograms:apiserver、kubelet、kube-proxy、scheduler、KCM 支持原生直方图(需开启特性门),大幅降低高基数延迟指标的存储成本。
- 监控指标改名(升级必改告警):
volume_operation_total_errors→volume_operation_errors_total;etcd_bookmark_counts→etcd_bookmark_total。凡是用到这两个指标的 Grafana 面板与告警规则,升级前先改。
5.4 Ingress NGINX 退役后的迁移路线
2026-03-24,Ingress NGINX 官方宣布退役:不再有新发布、Bug 修复或安全更新。这是 1.36 周边最该立刻行动的事项。
迁移到 Gateway API 是社区共识路线。官方提供了 ingress2gateway 工具做自动转换:
# 安装转换工具
go install sigs.k8s.io/ingress2gateway@latest
# 把现有 Ingress 转成 Gateway API 资源(HTTPRoute 等)
ingress2gateway print --input-file my-ingress.yaml
转换后要验证:Gateway API 的 HTTPRoute 区分了 ReferenceGrant 跨命名空间引用、Gateway 监听器 TLS 配置等,比 Ingress 更严谨。建议在测试集群先跑通再切生产。
六、升级实战与踩坑清单
1.36 变更面很广,下面是平台团队升级前必须过的清单。
6.1 版本依赖
| 组件 | 1.36 要求 |
|---|---|
| 构建用 Go | Go 1.26.x |
| etcd 客户端库 | v3.6.8(etcd 镜像同步 3.6.8) |
| CoreDNS | 1.14.2 |
| pause 镜像 | 3.10.2 |
etcd 升到 3.6.8 是硬性门槛,升级控制平面前先确认 etcd 集群健康。
6.2 自定义调度器插件适配(必做)
- 实现
PreBindPreFlight(返回PreBindPreFlightResult)。 PostFilter返回带被抢占 Pod 列表的PostFilterResult。- 全局替换
PodGroupInfo→PodGroupState。 - 检查是否依赖
SchedulerAsyncAPICalls(1.36 已禁用,有性能问题)。
6.3 DRA 用户:RBAC 与 ResourceSlice
- DRA 驱动/控制器需要更细粒度的 RBAC 才能更新
ResourceClaim状态——检查现有 ClusterRole。 - ResourceSlice 控制器发布集群范围资源时必须显式设置
ReconcilePoolWithName,「All nodes」不再是默认。
6.4 网络配置:StrictIPCIDRValidation
1.36 默认启用严格 IP/CIDR 校验:禁止前导零(如 010.000.000.005)和语义模糊的子网掩码。凡是 Service、EndpointSlice、CNI 配置里残留这类不规范写法的,升级前后都会报错。用 kubectl get svc,ep -A -o json | grep -E '010\.|0+\.' 之类的巡检提前清理。
6.5 关键 Bug 修复(值得关注)
- StatefulSet 并行 Pod 管理回归:禁用
MaxUnavailableStatefulSet特性门修复了 1.35 的回归——从 1.35 升上来且开了该门的,1.36 需确认行为。 - DRA 调度竞争:修复快速调度时同设备重复分配(见 3.1)。
- Sidecar 重启:修复 kubelet 重启后,带 sidecar + startupProbe 的 Pod 普通容器崩溃无法重启的问题。
- Server-Side Apply / HPA object metrics / Windows 双栈 LB 等多个修复。
6.6 废弃与移除
Service.spec.externalIPs:废弃,使用会告警。git-repo卷插件:默认禁用且无法重新启用(历史遗留,早该扔)。v1alpha1 WebhookAdmissionConfiguration:移除。metav1.FieldsV1的Raw字段直接访问:废弃,改用新访问器方法。- Kubeadm 移除 FlexVolume 内置支持:如需保留,得自定义 KCM 镜像并手动挂载卷插件目录。
七、总结与展望
把 1.36 的几个主角放在一起看,会发现一条清晰的演进主线:
Kubernetes 正在从「调度无状态服务」的控制平面,进化为「调度一切异构资源」的操作系统内核。
- DRA 多子特性 GA/默认启用 → GPU/FPGA/DPU 第一次有了原生、结构化、拓扑感知、可约束的调度语言。
- Workload/PodGroup + TAS + 整组抢占 → 分布式训练、大数据批处理这类「组调度」负载,不需要再外挂 Volcano 也能原生表达。
- InPlacePodVerticalScaling 默认启用 → 业务弹性从「删了重建」走向「原地热改」,中断趋近于零。
- MutatingAdmissionPolicy / UserNamespaces / SELinux GA → 准入与安全的内建化,Webhook 与 root 容器逐步退场。
而 Ingress NGINX 的退役,则像是一个时代的注脚:旧的、命令式、厂商各自为政的入口管理方式正在让位于 Gateway API 这类声明式标准。
对于平台工程师,我的建议很明确:
- 立刻盘点 集群里是否还在依赖 Ingress NGINX,制定 Gateway API 迁移时间表。
- 如果跑 AI/异构硬件,认真评估 DRA(优先列表 + 可消费容量已 GA),把 GPU 调度从自研 Webhook 里逐步迁出。
- 升级前 按本文第六章清单逐项核对,尤其调度器插件接口与监控指标改名。
- 观望 原生资源映射、TAS 等 Alpha 能力,它们定义了下一个版本的重心。
1.36 不会让 headlines 炸裂,但它把「资源感知」这块地基,悄悄浇成了混凝土。等大模型训练、异构推理、边缘 AI 在明年全面铺开时,你会感谢今天这个不起眼的版本。
参考:本文基于 Kubernetes 1.36 官方发布说明与社区深度解读整理,特性状态(Alpha/Beta/GA)以 1.36 为准。生产升级请以官方文档与你的发行版(如 kubeadm、RKE2、EKS/GKE/ACK)说明为最终依据。