Kubernetes v1.36「Haru」深度解析:4年磨一剑,从容器安全到 AI 原生的全面跃迁
2026年4月22日,Kubernetes 社区如约交付了 v1.36,代号 Haru——日语「春」之意。没有颠覆性的新范式,没有惊雷般的架构变革,却是一个把过去三四年埋下的种子一一催开的版本。71项增强,18项GA,26项Beta——关键词不是「扩张」,而是「收口」。这对运维团队来说,比新增一堆实验性特性更有价值:你可以少用几个第三方工具,少维护几套自研组件,平台本身正在替你兜底。
本文将从架构设计、生产实战、安全加固、AI/ML 基础设施四条主线,系统拆解这次更新的核心技术细节与落地价值。无论你是平台工程师、SRE、还是正在搭建 AI 训练/推理平台的开发者,都能找到可以直接上手的东西。
一、版本概览:为什么说 v1.36 值得认真对待
先看一组数字:
- 71项增强
- 18项毕业至 Stable(GA)
- 26项进入 Beta
- 25项新的 Alpha 功能
对比过去几个版本,v1.36 的 GA 数量尤其值得关注。过去三四年里处于 Alpha/Beta 阶段的老功能——Pod User Namespaces、Mutating Admission Policies、SELinux 卷标签优化——这次终于迎来了自己的「毕业季」。
对于在生产环境维护 Kubernetes 的团队,这意味着两件事:
- 运维工具链可以简化:过去需要借助第三方运行时(gVisor/Kata Containers)或自研 Webhook 才能实现的安全能力,现在 Kubernetes 原生就提供了稳定实现;
- 升级收益可以直接量化:不需要冒险跑实验性特性,在已有工作负载上开启这些 GA 功能,就能获得可感知的收益。
二、Pod User Namespaces:从 Alpha 到 GA,四年磨一剑
2.1 它解决了什么问题
这是 v1.36 最值得优先了解的特性,没有之一。
Pod User Namespaces 最早于 Kubernetes v1.25(2022年8月)进入 Alpha,经过四个版本的打磨,终于在 v1.36 毕业至 GA。
核心能力:每个 Pod 拥有独立的用户 ID 和组 ID 命名空间。容器内看起来是 root(UID 0)的进程,在宿主机层面只是一个无特权用户。
这意味着什么?传统容器模型中,容器内的 root 本质上就是宿主机的 root——或者更准确地说,是一个映射到宿主机特定 UID 范围的特权用户。一旦攻击者通过容器逃逸漏洞突破了隔离层,他立即获得了对宿主机上那个映射 UID 的完整控制权。历史上多个高危漏洞(如 container escape CVE)都建立在这个前提之上。
Pod User Namespaces 彻底改变了这个假设。启用后:
spec:
hostUsers: false # 启用 User Namespace
containers:
- name: app
image: my-app
容器内的 root(UID 0)映射到宿主机上的一个非特权 UID(通常是 60000+),即使攻击者成功逃逸,他拿到的也只是那个无特权身份,对宿主机几乎没有任何破坏能力。
2.2 技术原理:从内核到运行时的协作链路
Pod User Namespaces 的实现依赖 Linux 内核的用户命名空间(user namespace)特性。这项内核能力从 2013 年的 Linux 3.8 起就已经存在,但 Kubernetes 真正将它带入容器编排的标准化语义,经历了漫长的社区协作。
技术链路:
- 容器运行时层(containerd/cri-o):需要在创建容器时配置
LinuxUserNamespace字段,将容器进程加入独立的 UID/GID 映射; - kubelet 层:负责在 Pod Spec 中接收
hostUsers: false配置,并将其转换为运行时参数; - 内核层:内核负责实际隔离——容器内的 UID/GID 视图与宿主机视图完全解耦。
一个常见误解是:Pod User Namespaces 和 rootless container 是一回事。实际上 rootless container(如 rootless Docker)解决的是「非 root 用户运行 Docker daemon」的问题,而 Pod User Namespaces 解决的是「容器内进程的身份在宿主机层面如何映射」的问题。两者可以结合使用,但解决的是不同层面的安全问题。
2.3 实战:如何启用 User Namespaces
当前版本(v1.36)的 User Namespaces 有一些前置条件和注意事项:
前置条件:
- Linux 内核 ≥ 5.16(推荐 ≥ 6.0)
- 容器运行时支持 User Namespaces(containerd ≥ 1.7,cri-o ≥ 1.27)
- 节点上不能有 Pod 使用 HostNetwork 或 HostPID
启用步骤:
# Pod 级别启用
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
hostUsers: false # 启用 User Namespace
securityContext:
runAsUser: 0 # 容器内以 root 身份运行
runAsGroup: 0
containers:
- name: app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
兼容性注意事项:
⚠️ 多容器 Pod:同一个 Pod 内所有容器必须同时使用或不使用 User Namespace,不能混配;
⚠️ HostPath 和 HostPort:使用 User Namespace 时,某些 HostPath 挂载行为会发生变化;
⚠️ Volume 挂载:挂载的宿主机路径在容器内看到的权限可能与预期不同;
⚠️ 特权容器:hostUsers: false 与 privileged: true 互斥。
2.4 迁移路径与收益评估
对于已有集群,User Namespaces 的迁移成本是可控的——它只需要在 Pod Spec 中添加一行配置,不需要修改镜像或重建集群。
推荐迁移顺序:
- 第一阶段:在测试环境对无状态应用启用,观察兼容性;
- 第二阶段:对有安全合规需求的工作负载(多租户环境、金融系统、政企平台)优先启用;
- 第三阶段:全面推广到所有工作负载。
收益量化:
| 场景 | 传统隔离 | + User Namespaces |
|---|---|---|
| 容器逃逸后宿主机权限 | 完全控制 | 无特权用户身份 |
| 多租户隔离强度 | Pod Security Policy | 命名空间级别 root 隔离 |
| 合规报告 | 需要额外说明 | Kubernetes 原生保证 |
三、Mutating Admission Policies:告别 Webhook Server 的运维重负
3.1 痛点:Mutating Webhook 有多烦
写过生产级 Mutating Webhook 的工程师,对这套体系的「烦」应该深有体会:
运维负担清单:
- 维护一个独立的 HTTP Server(通常用 Go/Python 编写)
- 配置 TLS 证书轮换(证书过期会导致所有 Pod 创建失败)
- 处理 Webhook 的超时和失败策略(超时可能阻塞 API Server)
- 管理 Webhook Server 的高可用(单点故障影响整个集群)
- 持续监控 Webhook Server 的可用性和延迟
这一切,只是为了在 Pod 创建时自动注入几个标签,或者给容器设置默认的资源限制。
3.2 解决方案:原生 CEL 表达式
v1.36 将 MutatingAdmissionPolicy 推至 GA 并默认开启。变更逻辑可以直接用 Kubernetes 原生对象表达,不再需要外部 Webhook 服务:
# 使用 CEL 表达式定义 Mutating Policy
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: set-default-resources
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
operations: ["CREATE"]
applyTo:
- groups: [""]
kinds: ["Pod"]
resources: ["pods"]
mutation:
patches:
- patch: |
[{"op":"add","path":"/spec/containers/0/resources",
"value":{"limits":{"cpu":"100m","memory":"256Mi"},
"requests":{"cpu":"50m","memory":"128Mi"}}}]
patchesJson6902: false
更优雅的方式是用 CEL 表达式替代 JSON Patch:
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: inject-monitoring-label
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
applyTo:
- groups: [""]
kinds: ["Pod"]
mutation:
patches:
- expression: |
# 给所有 Pod 注入监控标签
if object.metadata.labels["app.monitoring/enabled"] == null {
object.metadata.labels["app.monitoring/enabled"] = "true"
}
patchesJson6902: false
3.3 性能对比:Webhook vs. 原生 Policy
| 维度 | Mutating Webhook | MutatingAdmissionPolicy |
|---|---|---|
| 部署复杂度 | 需要独立服务 + TLS | 纯 K8s 资源 |
| 延迟开销 | 5-20ms(HTTP + TLS) | <1ms(API Server 内联) |
| 可用性风险 | Webhook 崩溃可阻塞 API Server | 无外部依赖 |
| GitOps 支持 | 部分支持(Server 配置外置) | 完全声明式 |
| 维护成本 | 高(证书、版本、监控) | 低(仅维护 YAML) |
3.4 典型场景实战
场景一:强制资源限制
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: enforce-resource-limits
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
operations: ["CREATE"]
applyTo:
- groups: [""]
kinds: ["Pod"]
mutation:
patches:
- expression: |
# 给没有设置 CPU limit 的容器设置默认值
for c in object.spec.containers {
if c.resources.limits["cpu"] == null {
c.resources.limits["cpu"] = "200m"
}
if c.resources.limits["memory"] == null {
c.resources.limits["memory"] = "256Mi"
}
}
patchesJson6902: false
场景二:自动注入 Sidecar
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingAdmissionPolicy
metadata:
name: inject-istio-sidecar
spec:
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
applyTo:
- groups: [""]
kinds: ["Pod"]
mutation:
patches:
- expression: |
# 为带有特定标签的命名空间自动注入 istio-proxy
if object.metadata.namespace != null &&
object.metadata.namespace.endsWith("-prod") {
# 注入逻辑通过 JSON Patch 实现
}
patchesJson6902: false
四、OCI VolumeSource:AI/ML 场景的游戏规则改变者
4.1 老问题:模型权重怎么送进 Pod
在 AI/ML 场景中,如何把模型权重、配置文件、数据集等大文件高效地送进 Pod,一直是个工程难题。过去的解法各有缺陷:
| 方案 | 缺点 |
|---|---|
| 打包进容器镜像 | 主镜像体积膨胀,更新频率受限,仓库存储成本高 |
| initContainer 拉取 | 启动流程变复杂,错误处理困难 |
| ConfigMap/Secret | 单个对象体积限制(ConfigMap ≤1MiB,Secret ≤1MiB) |
| PV/PVC | 需要额外的存储基础设施 |
4.2 新范式:把镜像仓库当存储用
v1.36 GA 的 OCI VolumeSource 把这个问题的解法彻底改变了——将任意 OCI 镜像当作卷来引用:
apiVersion: v1
kind: Pod
metadata:
name: llm-inference
spec:
containers:
- name: inference
image: my-inference-server:latest
volumeMounts:
- name: model-weights
mountPath: /models
volumes:
- name: model-weights
image:
reference: my-registry.example.com/models/llama3-8b:v1
# 拉取凭证(如需要)
pullSecret: reg-secret
工作原理:Kubernetes 会像拉取容器镜像一样,把这个「模型镜像」从仓库拉下来,以只读卷的形式挂载到 Pod 中。打包、分发、缓存、版本管理——全部复用现有的镜像仓库基础设施。
4.3 深度解析:为什么这是 AI/ML 场景的里程碑
存储成本优化:模型权重通常在几 GB 到几十 GB 量级(Llama-3 70B 的量化版本约 40GB)。传统方案需要为每个 Pod 分配独立存储,而 OCI VolumeSource 受益于镜像层的共享机制——同一个仓库中的多个 Pod 可以共享镜像层的缓存,大幅降低存储和网络成本。
版本管理的简化:模型的版本管理天然就是「不可变」的——每个版本对应一个镜像 tag。回滚模型只需要修改 Pod Spec 中的镜像引用,一切符合 GitOps 原则。
多副本一致性:分布式推理场景中,所有 Pod 实例必须使用完全相同的模型权重。OCI VolumeSource 确保所有副本从同一个镜像拉取,天然保证一致性。
与现有工具链的整合:
# Python 示例:使用 skopeo 推送模型到镜像仓库
import subprocess
def push_model_to_registry(model_path: str, registry: str, tag: str):
"""将模型文件打包为 OCI 镜像并推送"""
# 1. 使用 umoci 或其他工具创建 OCI 镜像
result = subprocess.run([
"skopeo", "copy",
"--multi-arch=all",
f"oci:{model_path}",
f"docker://{registry}/models/my-model:{tag}"
], capture_output=True)
return result.returncode == 0
4.4 生产环境注意事项
⚠️ 拉取时间:首次拉取大型模型镜像可能需要较长时间(取决于仓库带宽),需要配合 Pre-pulling 策略或 initContainer 确保 Pod 启动时模型已就位;
⚠️ 仓库配额:模型镜像通常很大,需要确认镜像仓库的存储配额和拉取速率限制;
⚠️ 安全扫描:建议对模型镜像进行安全扫描,因为它们本质上也是容器镜像;
⚠️ 多架构支持:如果使用 GPU 推理,确保镜像支持对应架构(amd64/arm64),或为不同架构维护不同镜像。
五、DRA 增强:异构算力管理的完整闭环
5.1 DRA 可分片设备:从整机调度到精细分配
GPU 等硬件加速器价格昂贵,独占式分配常常造成严重的利用率浪费——一个 80GB 的 H100 显卡,跑一个只需要 8GB 显存的推理任务,剩余 72GB 只能空转。
v1.36 将 DRA 可分片设备(KEP-4815)推进到 Beta,允许将单个硬件加速器切分成多个逻辑单元:
# DeviceClass 定义(管理员配置)
apiVersion: resource.k8s.io/v1alpha3
kind: DeviceClass
metadata:
name: partitionable-gpu
spec:
selectors:
- cel:
expression: device.driver == "nvidia.com/gpu"
config:
- opaque:
domain: nvidia.com
parameters: |
{
"partition_type": "1g.5gb",
"max_partitions": 7
}
---
# 工作负载请求分片 GPU
apiVersion: v1
kind: Pod
metadata:
name: gpu-inference-small
spec:
containers:
- name: inference
image: tensorflow/tensorflow:latest
resources:
claims:
- name: gpu-partition
deviceClassName: partitionable-gpu
deviceSelectors:
- cel:
expression: device.attributes["nvidia.com/gpu.memory"] >= 5368709120
5.2 DRA 设备污点与容忍:从「谁都能用」到「精准授权」
DRA 设备污点与容忍(KEP-5055)也在 v1.36 进入 Beta 并默认开启:
# 给专用 GPU 节点打上污点(管理员操作)
kubectl taint nodes gpu-node-1 nvidia.com/gpu=reserved:NoSchedule
# 工作负载显式声明容忍
apiVersion: v1
kind: Pod
metadata:
name: ml-training-job
spec:
containers:
- name: trainer
image: pytorch/pytorch:latest
resources:
claims:
- name: gpu
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
两者结合,Kubernetes 在异构算力管理上已经具备了完整语义:谁可以用(DeviceClass 选择器)、能分多少(可分片设备)、谁能访问(污点与容忍)——GPU 调度的三个核心问题,第一次被原生能力完整覆盖。
5.3 架构图:DRA 分片的工作流程
┌─────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Pod A │ │ Pod B │ ┌──────────┐ │
│ │ (1g.5gb) │ │ (1g.5gb) │ │ Pod C │ │
│ │ │ │ │ │ (2g.10gb)│ │
│ └──────┬───────┘ └──────┬───────┘ └────┬─────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────────────────────────────┐ │
│ │ DRA Controller │ │
│ │ ┌────────────┐ ┌────────────┐ │ │
│ │ │ Partitioner │ │ Taint/Toler │ │ │
│ │ │ (KEP-4815) │ │ (KEP-5055) │ │ │
│ │ └────────────┘ └────────────┘ │ │
│ └──────────────────────┬──────────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────┐ │
│ │ NVIDIA GPU (H100) │ │
│ │ 80GB total │ │
│ │ ┌───┐ ┌───┐ ┌───┐ │ │
│ │ │5GB│ │5GB│ │10GB│ │ │
│ │ └───┘ └───┘ └───┘ │ │
│ │ PodA PodB PodC │ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────────────┘
六、安全增强全景:多层次防御体系的完善
6.1 IP/CIDR 校验收紧(KEP-4858)
非规范 IP 格式(如 010.000.001.005)和模糊 CIDR 值(如在期望 192.168.1.0/24 的上下文中出现 192.168.1.5/24),将不再被核心 Kubernetes 对象接受。
这个变更背后是 CVE-2021-29923 级别的安全隐患——历史上这些非规范格式在不同实现之间存在解释歧义,曾被用作攻击面。
影响范围排查:
#!/bin/bash
# 检查集群中可能存在的非规范 IP 表达
echo "=== 检查非规范 IP 表达 ==="
# 检查 Service externalIPs
echo "[1/3] 检查 Service externalIPs..."
kubectl get svc -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.externalIPs}{"\n"}{end}' | \
grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'
# 检查 Pod IP 配置
echo "[2/3] 检查 Pod IP 配置..."
kubectl get pods -A -o yaml | grep -E '^\s+podIP:' | \
grep -vE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$'
# 检查 NetworkPolicy
echo "[3/3] 检查 NetworkPolicy CIDR..."
kubectl get networkpolicies -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}'
echo "=== 检查完成 ==="
6.2 ServiceAccount Token 外部签名(GA)
对 PCI-DSS、FedRAMP、SOC 2 等合规框架有需求的团队,v1.36 GA 的外部 Token 签名能力(KEP-740)是一条清晰路径——将 token 签发委托给外部 KMS 或 HSM,kube-apiserver 本身不存储私钥:
apiVersion: apiserver.config.k8s.io/v1
kind: AuthenticationConfiguration
spec:
serviceAccountTokenGetter:
- name: external-signer
audiences:
- https://my-cluster.example.com
signer:
kubernetes.io/kube-apiserver-client:
# 外部签名配置(示例,具体字段取决于 KMS 插件)
kms:
name: my-kms-plugin
provider: "gcpkms"
6.3 Fine-grained Kubelet API Authorization(GA)
节点级安全能力的另一项重要增强。在「最小权限」架构上向前迈了一大步——kubelet API 的访问控制粒度从「所有经过认证的请求」细化到了「特定操作对应特定权限」。
6.4 安全加固检查清单
#!/bin/bash
# v1.36 安全配置检查脚本
echo "=== Kubernetes v1.36 安全配置检查 ==="
# 1. 检查是否使用了 gitRepo 卷(已移除)
echo "[1/6] 检查 gitRepo 卷使用情况..."
kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{range .spec.volumes[*]}{" volume: "}{.name}{" gitRepo: "}{.gitRepo}{"\n"}{end}{end}' | \
grep -A1 "gitRepo" | head -20
# 2. 检查 externalIPs 使用(v1.36 显示警告)
echo "[2/6] 检查 externalIPs 使用..."
kubectl get services --all-namespaces -o json | \
jq '.items[] | select(.spec.externalIPs != null) | {namespace: .metadata.namespace, name: .metadata.name, externalIPs: .spec.externalIPs}'
# 3. 检查 Ingress NGINX 部署(已退役)
echo "[3/6] 检查 Ingress NGINX..."
kubectl get deployments --all-namespaces -l app.kubernetes.io/name=ingress-nginx 2>/dev/null || echo " 无 Ingress NGINX 部署"
# 4. 检查 ServiceAccount Token 签名配置
echo "[4/6] 检查 ServiceAccount 配置..."
kubectl get serviceaccounts --all-namespaces -o json | \
jq '[.items[] | select(.metadata.annotations["kubernetes.io/service-account.name"] != null)] | length' 2>/dev/null || echo " 检查完成"
# 5. 节点 SELinux 状态
echo "[5/6] 检查节点操作系统..."
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.osImage}{"\n"}{end}'
# 6. 当前版本
echo "[6/6] 当前集群版本..."
kubectl version --short 2>/dev/null || kubectl version
echo "=== 检查完成 ==="
echo "如有任何问题,请参考官方升级指南:"
echo "https://kubernetes.io/docs/tasks/administer-cluster/upgrade/"
七、移除与弃用:升级前必须处理的事项
7.1 gitRepo 卷插件——永久移除
根因:安全漏洞——容器内以 root 身份执行代码的严重安全隐患。
迁移方案一:initContainer + git-sync
apiVersion: v1
kind: Pod
metadata:
name: app-with-git-config
spec:
volumes:
- name: git-config
emptyDir: {}
initContainers:
- name: git-sync
image: registry.k8s.io/git-sync/git-sync:v4.2.0
args:
- --repo=https://github.com/example/config-repo
- --branch=main
- --depth=1
- --period=30s
- --dest=.
volumeMounts:
- name: git-config
mountPath: /git
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: git-config
mountPath: /etc/config
readOnly: true
迁移方案二:ConfigMap/Secret(适合小文件)
# Python 工具:将 Git 仓库转换为 ConfigMap
import yaml
import subprocess
from pathlib import Path
class GitToConfigMap:
def __init__(self, repo_url: str, branch: str = "main"):
self.repo_url = repo_url
self.branch = branch
def sync(self, output_dir: str = "/tmp/config-repo"):
"""克隆仓库并生成为 ConfigMap YAML"""
subprocess.run([
"git", "clone", "--depth", "1", "--branch",
self.branch, self.repo_url, output_dir
], check=True, capture_output=True)
configmap = {
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": {"name": "git-config"},
"data": {}
}
for path in Path(output_dir).rglob("*"):
if path.is_file() and not path.name.startswith('.'):
# 跳过二进制文件和大型文件
if path.stat().st_size > 1024 * 1024: # >1MB
continue
rel = path.relative_to(output_dir)
configmap["data"][str(rel)] = path.read_text(encoding="utf-8", errors="ignore")
return yaml.dump(configmap, allow_unicode=True)
# 使用示例
if __name__ == "__main__":
tool = GitToConfigMap("https://github.com/example/config-repo")
print(tool.sync())
7.2 kube-proxy IPVS 模式——已移除
v1.35 弃用的 IPVS 模式在 v1.36 中被移除。继续使用的场景需要切换到 iptables 或 nftables 模式:
# 检查当前模式
kubectl get configmap kube-proxy -n kube-system -o yaml | grep mode
# 切换到 iptables 模式
kubectl edit configmap kube-proxy -n kube-system
# 修改 mode 为 "iptables"
7.3 Ingress NGINX——正式退役
重大事件:2026年3月24日,Kubernetes SIG Network 和安全响应委员会正式宣布退役 Ingress NGINX 项目。
退役原因:
- 维护团队资源不足
- 安全漏洞响应时间过长
- 社区转向更现代的 Gateway API
替代方案对比:
| 方案 | 成熟度 | 迁移成本 | 推荐场景 |
|---|---|---|---|
| Gateway API + Contour | 高 | 中 | 生产环境首选 |
| Gateway API + Envoy Gateway | 中 | 中 | 新项目推荐 |
| Traefik | 中 | 低 | 小规模集群 |
| HAProxy Ingress | 高 | 低 | 简单 HTTP/HTTPS 路由 |
迁移到 Gateway API 完整示例:
# Step 1: 安装 Gateway API CRD 和 Contour
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: contour
spec:
controllerName: projectcontour.io/gateway-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: production-gateway
namespace: projectcontour
spec:
gatewayClassName: contour
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- name: wildcard-cert
kind: Secret
---
# Step 2: 定义路由(替代原有的 Ingress 规则)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: webapp-route
namespace: default
spec:
parentRefs:
- name: production-gateway
namespace: projectcontour
sectionName: https
hostnames:
- "app.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /api
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: api-service
port: 8080
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: frontend-service
port: 80
- headers:
matches:
- type: RegularExpression
name: X-Canary
value: "true"
backendRefs:
- name: api-service-canary
port: 8080
weight: 100
八、性能优化:被忽视但影响深远的改进
8.1 SELinux 卷标签优化——从分钟级到秒级
这个从 v1.27 就进入 Beta 的特性终于在 v1.36 稳定。原理是使用 mount -o context=XYZ 选项替代递归文件重标签:
apiVersion: v1
kind: Pod
metadata:
name: selinux-optimized-app
spec:
securityContext:
seLinuxOptions:
level: "s0:c123,c456"
seLinuxChangePolicy: MountOption # 关键配置
containers:
- name: app
image: my-app:latest
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: data-pvc
性能对比:
| 场景 | v1.35 之前 | v1.36 |
|---|---|---|
| 10GB PVC 首次挂载 | 45-90秒(递归重标签) | <2秒(挂载时应用标签) |
| Pod 启动时间(有大卷) | 数分钟 | 秒级 |
| 节点重启后 Pod 调度 | 严重延迟 | 正常 |
⚠️ 注意事项:混合使用特权和非特权 Pod 共享同一卷时可能导致 SELinux 标签冲突。需要正确设置 seLinuxChangePolicy 字段。
8.2 Pod 级原地伸缩(Beta)
v1.36 将 Pod 级别的 CPU/内存在线伸缩推进到 Beta(面向 cgroup v2 环境):
apiVersion: v1
kind: Pod
metadata:
name: scalable-service
spec:
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: NotRequired
containers:
- name: app
image: my-app:latest
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
在原地伸缩模式下,修改 Pod 的资源请求时不需要重启容器——这对有状态服务、数据库和高可用应用的运维体验是质的提升。
九、生产升级路径:从检查到执行
9.1 升级前检查流程
#!/bin/bash
# Kubernetes v1.36 升级前完整检查
set -e
echo "=========================================="
echo " Kubernetes v1.36 升级前检查"
echo "=========================================="
# 检查 1: gitRepo 卷使用
echo "[1/7] 检查 gitRepo 卷..."
GITREPO_PODS=$(kubectl get pods --all-namespaces -o jsonpath='{range .items[*]}{.metadata.namespace}{" "}{.metadata.name}{"\n"}{range .spec.volumes[*]}{.gitRepo}{"\n"}{end}{end}' | grep -v "^$" | grep -v "^ " | grep -v "^$")
if [ -n "$GITREPO_PODS" ]; then
echo " ⚠️ 发现使用 gitRepo 卷的 Pod,必须先迁移!"
echo "$GITREPO_PODS"
else
echo " ✅ 无 gitRepo 卷使用"
fi
# 检查 2: externalIPs 使用
echo "[2/7] 检查 externalIPs..."
EXT_IPS=$(kubectl get services --all-namespaces -o json | \
jq -r '.items[] | select(.spec.externalIPs != null and (.spec.externalIPs | length) > 0) | "\(.metadata.namespace)/\(.metadata.name)"')
if [ -n "$EXT_IPS" ]; then
echo " ⚠️ 发现使用 externalIPs 的 Service(v1.36 显示警告):"
echo "$EXT_IPS"
else
echo " ✅ 无 externalIPs 使用"
fi
# 检查 3: Ingress NGINX
echo "[3/7] 检查 Ingress NGINX..."
INGRESS=$(kubectl get deployments --all-namespaces \
-l app.kubernetes.io/name=ingress-nginx \
-o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}')
if [ -n "$INGRESS" ]; then
echo " ⚠️ 发现 Ingress NGINX 部署,已退役,建议迁移至 Gateway API:"
echo "$INGRESS"
else
echo " ✅ 无 Ingress NGINX 部署"
fi
# 检查 4: kube-proxy 模式
echo "[4/7] 检查 kube-proxy 模式..."
MODE=$(kubectl get configmap kube-proxy -n kube-system -o jsonpath='{.data.config}' | \
jq -r '.mode // "iptables"')
echo " 当前模式: $MODE"
if [ "$MODE" = "ipvs" ]; then
echo " ⚠️ IPVS 模式已在 v1.36 移除,必须切换到 iptables 或 nftables"
fi
# 检查 5: etcd 备份
echo "[5/7] 检查 etcd 备份状态..."
ETCD_PODS=$(kubectl get pods -n kube-system -l component=etcd -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}')
echo " etcd 节点: $ETCD_PODS"
echo " ⚠️ 请确认已执行: kubectl exec -n kube-system etcd-<node> -- etcdctl snapshot save /var/lib/etcd/snapshot.db"
# 检查 6: 当前版本
echo "[6/7] 当前集群版本..."
kubectl version --short 2>/dev/null || kubectl version
# 检查 7: 节点 OS 兼容性
echo "[7/7] 节点 OS 检查..."
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.osImage}{"\t"}{.status.nodeInfo.kernelVersion}{"\n"}{end}'
echo ""
echo "=========================================="
echo " 检查完成"
echo "=========================================="
9.2 推荐的升级步骤
标准升级路径(假设从 v1.34/v1.35 升级):
创建 etcd 快照(必须!)
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \ --cert=/etc/kubernetes/pki/etcd/server.crt \ --key=/etc/kubernetes/pki/etcd/server.key \ --cacert=/etc/kubernetes/pki/etcd/ca.crt \ snapshot save /var/lib/etcd/snapshot-$(date +%Y%m%d).db升级控制平面组件
# 使用 kubeadm kubeadm upgrade plan v1.36.0 kubeadm upgrade apply v1.36.0升级 kubelet
# 每台节点逐一执行 kubectl drain <node> --ignore-daemonsets --delete-emptydir-data apt-get install -y kubelet=1.36.0-* systemctl restart kubelet kubectl uncordon <node>验证升级
kubectl get nodes # 确认所有节点状态为 Ready,版本为 v1.36.0
十、总结与展望
Kubernetes v1.36「Haru」的核心价值,可以用三句话总结:
第一句:安全能力从「可选增强」变成「原生内置」。Pod User Namespaces、ServiceAccount 外部签名、IP/CIDR 校验收紧——过去需要借助第三方运行时或自研组件才能实现的安全能力,现在 Kubernetes 自身就能兜底。对多租户、金融、政企、合规场景,这是直接可用的基础设施升级。
第二句:AI/ML 基础设施正式进入 Kubernetes 的核心语义。OCI VolumeSource 解决了模型分发的老大难问题,DRA 可分片设备让 GPU 资源从「整机独享」走向「按需切分」,Gateway API 的流量治理能力支撑起金丝雀发布和 A/B 测试。当 KubeCon 的主题词从「Cloud Native」演变为「AI Native」,Kubernetes 正在用它最擅长的方式——标准化和平台化——为 AI 工作负载构建基础设施底座。
第三句:运维负担的结构性降低。Mutating Admission Policies 让你不再需要维护 Webhook Server 集群,SELinux 卷标签优化让大卷 Pod 的启动时间从分钟级降到秒级,Pod 级原地伸缩让你不需要为了调整资源限制而重启服务。这些改进单独看都不大,但累积起来,对日常运维体验是质的提升。
升级建议:
- 生产环境建议在官方发布后 2-4 周进行升级(有充分的生产案例验证后)
- 先在测试环境验证所有工作负载兼容性
- 优先处理:gitRepo 卷迁移、Ingress NGINX 到 Gateway API 的迁移路线图
- 关注警告:externalIPs 弃用警告(计划在 v1.43 完全移除)
Kubernetes 正在从「容器编排平台」进化为「面向 AI 时代的企业级云原生操作系统」。v1.36 是这条进化路上的一个重要节点——它不追求惊雷般的变革,而是把过去数年积累的能力一一兑现。春山可望,稳中有为。
参考链接: