编程 Kubernetes v1.36 深度拆解:当云原生学会「原生安全」——User Namespaces GA、CEL 准入策略与 Gateway API 如何重写集群治理的心智模型

2026-07-16 02:12:48 +0800 CST views 9

Kubernetes v1.36 深度拆解:当云原生学会「原生安全」——User Namespaces GA、CEL 准入策略与 Gateway API 如何重写集群治理的心智模型

2026 年的第一个 Kubernetes 大版本 v1.36(代号 Haru)已经落地。它没有带来花哨的 UI,却在三个工程师每天都会痛的方向上悄悄改写了规则:原生安全边界、准入控制的去 Webhook 化、以及 AI 工作负载成为一等公民。本文从工程视角拆解 v1.36 的 70 项增强里最值得你熬夜升级的 18 项 Stable 特性,配可落地的 YAML 实战,帮你在生产集群升级前把账算清楚。

一、背景:为什么 v1.36 是「治理拐点」而非普通迭代

先说一个残酷的事实:过去五年,Kubernetes 的「安全」和「网络入口」几乎完全建立在外部进程之上。

  • 你想给所有 Pod 强制打标签、注入 sidecar、改镜像仓库?写一个 MutatingAdmissionWebhook,搭一套 HTTPS 服务,管证书、管高可用、管超时。
  • 你想禁止容器以 root 跑、想做镜像白名单?同样,再写一个 ValidatingAdmissionWebhook。
  • 你想暴露一个 HTTP 服务?装 Ingress NGINX,一个用 Go 写的、带 Lua 的、承载了全公司南北向流量的巨型控制器。

这套架构在 2018 年很先进,但在 2026 年已经显出疲态:每多一个 Webhook,apiserver 的写路径就多一跳网络往返;每多一个 Ingress Controller,就意味着多一个需要跟 CVE 赛跑的攻击面。v1.36 的发布说明里有一句话点题——「重点聚焦安全加固、AI/ML 工作负载、以及大规模 API 的可扩展性」。翻译过来就是:Kubernetes 正在把「原本外包出去的能力」收回到控制平面内部,变成原生对象。

v1.36 一共包含 70 项增强功能:18 项 Stable、25 项 Beta、25 项 Alpha。本文聚焦已经 GA 或默认开启的特性,因为它们才是你升级后立刻能用、且应该立刻用上的东西。

二、核心概念:v1.36 的四块基石

2.1 User Namespaces GA —— 容器逃逸后,你拿不到节点

先纠正一个常见误解:「容器不是沙箱」。一个以 root 运行的容器,如果利用内核漏洞逃逸到宿主机,它在宿主机上也是 UID 0——也就是节点的实际 root。传统的 runAsNonRoot 只是「不让它主动以 root 启动」,并没有在 UID 层面真正隔离。

User Namespaces 的底层机制是 Linux 的 user_namespaces:它把容器内的 UID/GID 范围映射到宿主机上一个完全非特权(unprivileged)的 UID 区间。即使容器内是 root(UID 0),在宿主机视角下它只是某个随机普通用户(比如 UID 100000+)。逃逸成功,你拿到的也只是宿主机上的一个nobody,动不了节点。

v1.36 中这项能力正式 GA。它的开关极其简单:PodSpec.hostUsers: false

2.2 CEL 准入策略 —— 把 Webhook 请出热路径

Kubernetes 在 1.26 引入了 ValidatingAdmissionPolicy(用 CEL 表达式做校验,1.30 GA),v1.36 则把它的兄弟 MutatingAdmissionPolicy 推到了 GA。这意味着「变更类」准入逻辑(注入、默认值、重写)也可以不再依赖外部 Webhook 服务,而是写成原生对象,由 apiserver 进程内用 CEL 求值。

  • Webhook 模式:apiserver → 网络调用你的服务 → 你的服务返回 patch → apiserver 应用。每一写请求一跳网络,延迟、可用性、证书全要管。
  • CEL Policy 模式:apiserver 直接在自己进程里跑一段受限的表达式,零网络往返,毫秒级,且表达式语言被沙箱化,无法做 IO。

2.3 Gateway API 接棒 Ingress NGINX

2026 年 3 月 24 日,SIG Network 与安全响应委员会正式宣布退役 Ingress NGINX:不再发版、不再修 bug、不再修 CVE。存量部署还能跑,但生产环境已经被「建议迁移」。接棒者是 Gateway API——一个角色导向、可移植、面向 L4/L7 的官方标准(gateway.networking.k8s.io)。

2.4 DRA(Dynamic Resource Allocation)成为 AI Infra 的心脏

Dynamic Resource Allocation 自 1.26 引入,v1.36 里迎来一波集中毕业:可消费容量(Consumable Capacity)GA、设备优先列表(Prioritized List)GA、管理员访问 GA、设备绑定条件/污点容忍 Beta。对跑大模型训练/推理的团队,这意味着 GPU、NPU、FPGA 这类「非 CPU 内存类」硬件,终于有了和 Pod 生命周期深度绑定、可分区、可拓扑感知的调度原语。

三、架构分析:它们到底怎么工作

3.1 User Namespaces 的映射链路

容器进程 (UID 0, 看起来是 root)
        │  user_namespaces 映射
        ▼
宿主机 UID 100xxx (非特权普通用户)
        │
        ▼
即便容器逃逸,也只是一个普通用户,无法操作节点

开启后,kubelet 会为该 Pod 创建一个独立的 user namespace,并把容器内的 root 映射到宿主机的一个非特权 UID。PodSecurityContext 里还能配合 namespaceOptions.user 控制命名空间级别行为。关键点:它和 runAsNonRootseccompProfilecapabilities 是互补关系,不是替代。User Namespaces 解决「即使出事也伤害有限」,前三者解决「尽量别出事」。

3.2 CEL 准入策略的求值模型

CEL(Common Expression Language)是一套无状态、无副作用的表达式语言,最初用于 CRD 的 x-kubernetes-validations。它的安全模型决定了它不能发网络请求、不能读文件、不能调系统时间——这恰恰是做准入控制想要的:可预测、低延迟、不会把 apiserver 卡死。

ValidatingAdmissionPolicyvalidations[].expression 返回布尔;MutatingAdmissionPolicymutations 计算要施加的补丁。两者都通过 matchConstraints 声明「对哪些资源、哪些操作生效」,通过 Binding 对象声明「在哪些命名空间生效」。validationActions: [Deny|Audit|Warn] 让你先 Audit 观察再 Deny 上线,这个灰度能力在生产环境极关键。

3.3 Gateway API 的角色模型

Ingress 只有一份扁平的 Ingress 资源,把「基础设施(谁拥有 LB)」和「路由(应用怎么暴露)」混在一起。Gateway API 拆成两层:

  • Gateway:由基础设施/平台团队拥有,描述「有一个监听器在 443 端口、用哪个证书、绑定哪个 GatewayClass」。
  • HTTPRoute / GRPCRoute / TCPRoute:由应用团队拥有,描述「example.com 的 /api 转到 web-svc:80」。

这种「角色导向」天然解决了多租户、多团队共享一个 LB 的权限问题,也是 GAMMA(Gateway API for Mesh Management and Administration)把东西向流量也纳入同一套 API 的基础。

3.4 DRA 的资源生命周期

DeviceClass (集群级:描述一类硬件,如 nvidia-gpu)
     │
     ▼
ResourceClaimTemplate (工作负载级:每次 Pod 创建动态生成 Claim)
     │
     ▼
ResourceClaim (具体的一次资源申请,绑定到某个节点上的具体设备)
     │
     ▼
Pod.spec.containers[].resources.claims 引用该 Claim

DRA 用「结构化参数(Structured Parameters)」让设备插件只声明「我有什么设备、什么属性」,调度器基于这些属性做匹配,而不再依赖旧的 Device Plugin 逐节点上报的粗粒度模型。v1.36 的「可分区容量」允许一张 80GB 显存的卡被两个 Pod 各分 40GB;「优先列表」让调度器在多个候选设备间按管理员定义的优先级选优;「拓扑感知」则保证两个 GPU Pod 被调度到同一 NUMA 域以减少跨节点通信。

四、代码实战:把 v1.36 用到生产里

4.1 开启 User Namespaces,把 root 关进笼子

apiVersion: v1
kind: Pod
metadata:
  name: hardened-app
spec:
  # v1.36 GA:false 表示让该 Pod 运行在独立的 user namespace 中
  # 容器内 root(UID 0) 会被映射到宿主机上一个非特权 UID
  hostUsers: false
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: registry.example.com/app:1.4.0
    securityContext:
      allowPrivilegeEscalation: false
      capabilities:
        drop: ["ALL"]
      readOnlyRootFilesystem: true

注意:hostUsers: false 与「需要真正主机 root 权限」的特权工作负载(如某些 CNI、存储插件 DaemonSet)不兼容,务必先在非关键 DaemonSet 上灰度。

4.2 用 ValidatingAdmissionPolicy 强制 Deployment 带团队标签(GA,可直接用)

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: require-team-label
spec:
  matchConstraints:
    resourceRules:
    - apiGroups: ["apps"]
      apiVersions: ["v1"]
      operations: ["CREATE", "UPDATE"]
      resources: ["deployments"]
  validations:
  - expression: >-
      object.spec.template.metadata.labels.exists(
        k, k.startsWith('team.')
      )
    message: "Deployment 必须带 team.* 标签,例如 team.payment"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: require-team-label-binding
spec:
  policyName: require-team-label
  # 先 Audit 观察拒绝率,稳定后改为 Deny
  validationActions: ["Audit"]
  matchResources:
    namespaceSelector:
      matchLabels:
        policy: enforced

这条策略用一行 CEL 表达式,替代了你原本要写几百行 Go + 证书管理的一个 Webhook。最妙的是 validationActions: ["Audit"]——上线先只记录不拒绝,从监控里看有多少 Deployment 不合规,再切 Deny。这是 Webhook 时代很难优雅做到的灰度。

4.3 MutatingAdmissionPolicy:自动注入sidecar(GA,注意核对 apiVersion)

v1.36 中 Mutating 类策略正式 GA。其结构与 Validating 平行,但用 mutations 计算补丁。下面示例演示「给打了 inject.metrics: "true" 的 Pod 自动挂一个采集 sidecar」的写法骨架(具体 apiVersion 与 mutations 字段以你集群 kubectl api-versions 实际输出为准,下面以 v1 示意):

apiVersion: admissionregistration.k8s.io/v1   # 以 1.36 实际发布为准
kind: MutatingAdmissionPolicy
metadata:
  name: inject-metrics-sidecar
spec:
  matchConstraints:
    resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      operations: ["CREATE"]
      resources: ["pods"]
  # mutations 通过 CEL 计算要施加到 Pod 的补丁(patch)
  # 真实字段名/补丁语法请以 1.36 API 参考为准
  variables:
  - name: needInject
    expression: "object.metadata.labels['inject.metrics'] == 'true'"
  mutations:
  - patch: >-
      [{'op':'add','path':'/spec/containers/-',
        'value':{'name':'metrics-agent','image':'registry.example.com/agent:2.1'}}]
    where: "variables.needInject"

工程建议:Mutating 策略一旦写错,可能把全集群的 Pod 都改坏。请务必先在单个测试命名空间、配合 validationActions 的审计模式验证,再扩大范围。

4.4 从 Ingress NGINX 迁移到 Gateway API

旧写法(Ingress NGINX,已退役):

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

新写法(Gateway API,v1.36 推荐):

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: prod-gateway
spec:
  gatewayClassName: envoy   # 由平台团队管理,绑定具体 LB/控制器
  listeners:
  - name: https
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      certificateRefs:
      - name: example-com-cert
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web
spec:
  parentRefs:
  - name: prod-gateway
  hostnames:
  - "example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: web-svc
      port: 80

迁移收益不只是「换个 API」:Gateway 与 HTTPRoute 分离让平台团队拥有 LB、应用团队拥有路由backendRefs 直接引用 Service,不再依赖 Controller 私有的 annotation;并且同一套 HTTPRoute 模型能平滑扩展到 GRPC、TCP、甚至服务网格(GAMMA)。

4.5 用 DRA 给训练任务申请 GPU(v1.36 增强后)

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: gpu-claim
spec:
  spec:
    devices:
      requests:
      - name: gpu
        deviceClassName: nvidia-h100   # 集群级 DeviceClass,由设备插件注册
---
apiVersion: v1
kind: Pod
metadata:
  name: llm-trainer
spec:
  containers:
  - name: trainer
    image: registry.example.com/trainer:torch2
    command: ["python", "train.py"]
    resources:
      claims:
      - name: gpu
        resourceClaimTemplateName: gpu-claim

在 v1.36 里,你可以进一步利用:

  • 可分区容量(GA):一张 H100 80GB 通过 DeviceClassconsumeCapacity 配置,被两个 Pod 各申请 40GB,显存利用率翻倍。
  • 设备优先列表(GA)DeviceClass 上声明优先用空闲卡、再用忙卡,调度器自动选优。
  • 拓扑感知调度(TAS, Alpha):把一组 Pod 约束到同一 NUMA/同一交换机的 GPU 上,把跨卡通信延迟压到最低。

4.6 组调度(Gang Scheduling)用 Workload / PodGroup

v1.36 引入 scheduling.k8s.io/v1alpha2 的 Workload / PodGroup 抽象,配合调度器的「负载感知抢占」——要么一组 Pod 全调度成功,要么全不调度,避免「分布式训练申请到 7 张卡、第 8 张一直 pending」的资源碎片死锁:

apiVersion: scheduling.k8s.io/v1alpha2
kind: Workload
metadata:
  name: dist-train
spec:
  podSets:
  - name: workers
    template:
      spec:
        # 这里放普通 Pod template
        containers:
        - name: worker
          image: registry.example.com/worker:1.0
    count: 8

五、性能优化:v1.36 让你「白捡」的收益

  1. 准入延迟归零:把 Mutating/Validating Webhook 换成 CEL Policy 后,写路径少了一次网络往返。在大规模集群(每秒上千写请求)里,这直接降低 apiserver p99 延迟,并消除「Webhook 挂了导致全集群写阻塞」的单点故障。

  2. 调度器 PreBind 并行:v1.36 调度框架支持 PreBind 插件并行执行。自定义调度插件需在 PreBindPreFlight 中返回 PreBindPreFlightResult{AllowParallel: true} 才能享受并行;否则保持串行。对有多步绑定逻辑(卷绑定、设备分配、网络准备)的插件,这是实打实的吞吐提升。

  3. DRA 可分区容量:如前所述,显存/设备被切片复用,单位硬件承载的工作负载数量上升,等于变相「省卡」。

  4. 监控指标重命名volume_operation_total_errorsvolume_operation_errors_totaletcd_bookmark_countsetcd_bookmark_total升级前请更新你的 Grafana 面板和告警规则,否则升级后图表会变空白——这是最容易被忽略、却最先被发现的生产事故。

  5. ServiceAccount 令牌外部签名 GA:可以把 SA 令牌的签名外包给外部 KMS,配合短有效期令牌,进一步收紧身份面。

六、升级前的 checklist(踩坑预警)

  • Ingress NGINX 已退役:盘点所有 ingressClassName: nginx 的 Ingress,制定 Gateway API 迁移排期。
  • gitRepo 卷驱动永久禁用:任何用 gitRepo volume 的 Pod 直接失败,改用 initContainer + emptyDir 拉取代码。
  • Service.spec.externalIPs 弃用:确认是否依赖 externalIPs,有则改用 LoadBalancer 或 Gateway。
  • SELinux 卷标签性能优化:验证自定义 SELinux 策略兼容新的挂载行为,否则可能 Pod 起不来。
  • Kubeadm 移除 FlexVolume:依赖 FlexVolume 的存储需迁移到 CSI。
  • 监控指标改名:更新面板与告警。
  • 自定义调度插件:确认 PreBind 插件是否适配并行执行接口。

七、总结与展望:Kubernetes 正在变成 AI Infra 的控制平面

把 v1.36 的四块基石连起来看,一条清晰的主线浮现:Kubernetes 正在把「原本靠外围组件硬凑的能力」,收编为原生、安全、可组合的控制平面原语

  • User Namespaces 让「即使出事也伤害有限」成为默认;
  • CEL 准入策略让策略即代码,且零运维成本;
  • Gateway API 让南北向、东西向流量终于有了统一语言;
  • DRA 让 GPU/NPU 这类 AI 硬件成为与 CPU/内存同级的调度公民。

这背后是云原生的重心迁移:从「能把容器跑起来」,到「能安全、高效、可治理地跑 AI 负载」。v1.36 不是终点——Workload/PodGroup 的组调度还在 Alpha,DRA 的原生资源映射(把设备映射成 CPU/内存)还在 Alpha。但方向已经写明:未来的 K8s,是 AI 基础设施的操作系统

对于一线工程师,我的建议很直接:别等 Webhook 出问题才动。先把一两条高频校验规则从 Webhook 迁到 CEL Policy(先 Audit 后 Deny),把入口从 Ingress NGINX 迁到 Gateway API,给训练任务接上 DRA。这三步做完,你的集群会明显更安全、更便宜、也更省心。

延伸阅读:Kubernetes 官方博客 v1.36 release notes、SIG Auth 的 CEL Admission Policy KEP、SIG Network 的 Gateway API 文档、SIG Node 的 DRA 设计提案。所有 GA 特性的精确 API 版本,请以你集群 kubectl api-versions 的实际输出为准。

推荐文章

GROMACS:一个美轮美奂的C++库
2024-11-18 19:43:29 +0800 CST
前端开发中常用的设计模式
2024-11-19 07:38:07 +0800 CST
Go 单元测试
2024-11-18 19:21:56 +0800 CST
Vue3中如何处理SEO优化?
2024-11-17 08:01:47 +0800 CST
介绍25个常用的正则表达式
2024-11-18 12:43:00 +0800 CST
Vue3中如何实现国际化(i18n)?
2024-11-19 06:35:21 +0800 CST
liunx服务器监控workerman进程守护
2024-11-18 13:28:44 +0800 CST
7种Go语言生成唯一ID的实用方法
2024-11-19 05:22:50 +0800 CST
pin.gl是基于WebRTC的屏幕共享工具
2024-11-19 06:38:05 +0800 CST
虚拟DOM渲染器的内部机制
2024-11-19 06:49:23 +0800 CST
程序员茄子在线接单