编程 Kubernetes 1.36 深度拆解:当云原生控制平面进入「资源感知」时代——从 DRA 设备污点与优先列表到调度器并行 PreBind、从原地垂直缩容到 Ingress NGINX 退役的工程全貌(2026)

2026-07-18 01:48:59 +0800 CST views 20

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,但它有三个结构性缺陷:

  1. 不透明:GPU 对你来说只是一个整数,调度器不知道它是 A100 还是 H100,不知道它的显存、NVLink 拓扑、是否健康。
  2. 不可分:你没法要「半个 GPU」或「一张卡上的 40GB 显存」,整数资源要么全给要么不给。
  3. 无拓扑:多卡训练时,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)BetaDevice 分配后有结构化状态条件,可观测
DRA 设备污点与容忍(Device Taints & Tolerations)BetaDevice 可打污点,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)AlphaDevice 属性支持列表类型

这张表读下来,信号非常明确:「可消费容量 + 优先列表 + 设备绑定条件」三项 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/v1alpha2Workload 和 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"]

注意 prioritizationtolerations 是 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}' 观察分配进度(ProposedInProgressInfeasible/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_errorsvolume_operation_errors_totaletcd_bookmark_countsetcd_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 要求
构建用 GoGo 1.26.x
etcd 客户端库v3.6.8(etcd 镜像同步 3.6.8)
CoreDNS1.14.2
pause 镜像3.10.2

etcd 升到 3.6.8 是硬性门槛,升级控制平面前先确认 etcd 集群健康。

6.2 自定义调度器插件适配(必做)

  • 实现 PreBindPreFlight(返回 PreBindPreFlightResult)。
  • PostFilter 返回带被抢占 Pod 列表的 PostFilterResult
  • 全局替换 PodGroupInfoPodGroupState
  • 检查是否依赖 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.FieldsV1Raw 字段直接访问:废弃,改用新访问器方法。
  • 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 这类声明式标准。

对于平台工程师,我的建议很明确:

  1. 立刻盘点 集群里是否还在依赖 Ingress NGINX,制定 Gateway API 迁移时间表。
  2. 如果跑 AI/异构硬件,认真评估 DRA(优先列表 + 可消费容量已 GA),把 GPU 调度从自研 Webhook 里逐步迁出。
  3. 升级前 按本文第六章清单逐项核对,尤其调度器插件接口与监控指标改名。
  4. 观望 原生资源映射、TAS 等 Alpha 能力,它们定义了下一个版本的重心。

1.36 不会让 headlines 炸裂,但它把「资源感知」这块地基,悄悄浇成了混凝土。等大模型训练、异构推理、边缘 AI 在明年全面铺开时,你会感谢今天这个不起眼的版本。


参考:本文基于 Kubernetes 1.36 官方发布说明与社区深度解读整理,特性状态(Alpha/Beta/GA)以 1.36 为准。生产升级请以官方文档与你的发行版(如 kubeadm、RKE2、EKS/GKE/ACK)说明为最终依据。

推荐文章

PostgreSQL日常运维命令总结分享
2024-11-18 06:58:22 +0800 CST
前端如何优化资源加载
2024-11-18 13:35:45 +0800 CST
Python中何时应该使用异常处理
2024-11-19 01:16:28 +0800 CST
微信内弹出提示外部浏览器打开
2024-11-18 19:26:44 +0800 CST
程序员茄子在线接单