跳过正文
Kubernetes v1.33 新特性深度解读:GA 特性全览与升级指南

Kubernetes v1.33 新特性深度解读:GA 特性全览与升级指南

·1222 字·6 分钟·
目录

Kubernetes v1.33 在 2025 年 4 月发布,这一版把几个磨了好几代的特性升到了 GA。挑几个我觉得做运维会直接用到的拆开说说。


In-Place Pod Vertical Scaling(GA)
#

背景与痛点
#

传统 Kubernetes 调整 Pod 的 CPU 或内存 Requests/Limits,唯一办法是删除旧 Pod、创建新 Pod。这对有状态服务是个严重问题:数据库实例、缓存服务、长连接 WebSocket 服务,每次扩容都意味着连接中断和短暂不可用。

即使配合 PDB(Pod Disruption Budget)和滚动更新,调整资源规格也至少需要一轮 Pod 替换,这在业务高峰期是不可接受的操作窗口。

功能说明
#

In-Place Pod Vertical Scaling 允许在不重启 Pod 的情况下,动态调整已运行 Pod 的 CPU 和内存资源配额。核心机制是:

  • 修改 spec.containers[].resources 中的 requestslimits
  • kubelet 通过 CRI 接口向容器运行时发送 UpdateContainerResources 调用
  • 对于 CPU,内核 cgroup 的 cpu.shares / cpu.cfs_quota_us 即时更新,无需重启
  • 对于内存,同样更新 cgroup memory.limit_in_bytes,但内存缩减存在限制(见注意事项)

每个容器新增 resizePolicy 字段,声明各资源类型的调整策略:

resizePolicy:
  - resourceName: cpu
    restartPolicy: NotRequired   # CPU 调整无需重启
  - resourceName: memory
    restartPolicy: RestartContainer  # 内存调整需要重启容器

完整配置示例
#

apiVersion: v1
kind: Pod
metadata:
  name: mysql-standalone
  namespace: production
spec:
  containers:
  - name: mysql
    image: mysql:8.0
    resources:
      requests:
        cpu: "2"
        memory: "4Gi"
      limits:
        cpu: "4"
        memory: "8Gi"
    resizePolicy:
    - resourceName: cpu
      restartPolicy: NotRequired
    - resourceName: memory
      restartPolicy: RestartContainer
    env:
    - name: MYSQL_ROOT_PASSWORD
      valueFrom:
        secretKeyRef:
          name: mysql-secret
          key: password

运行时调整资源(直接 patch spec 即可):

# 在线扩容 CPU,不重启 Pod
kubectl patch pod mysql-standalone -n production --type=json -p='[
  {
    "op": "replace",
    "path": "/spec/containers/0/resources/requests/cpu",
    "value": "3"
  },
  {
    "op": "replace",
    "path": "/spec/containers/0/resources/limits/cpu",
    "value": "6"
  }
]'

# 查看调整状态
kubectl get pod mysql-standalone -n production -o jsonpath='{.status.resize}'
# 输出: InProgress -> Deferred -> Infeasible -> "" (成功)

Pod status 新增 resize 字段反映调整进度:

status:
  resize: ""          # 空字符串表示调整完成或无进行中的调整
  containerStatuses:
  - name: mysql
    allocatedResources:
      cpu: "3"        # 实际分配的资源(可能与 spec 不同步)
      memory: "4Gi"
    resources:
      requests:
        cpu: "3"
        memory: "4Gi"

与 VPA 的关系
#

In-Place 特性本身是底层机制,VPA(Vertical Pod Autoscaler)在 Updater 组件中已开始利用此特性实现"原地更新"模式,减少 Pod 驱逐次数。生产中推荐组合使用:VPA 负责分析和推荐,In-Place 负责无损执行。

注意事项
#

  1. 内存缩减风险:缩减内存 Limit 时,如果容器实际使用量超过新 Limit,内核的 OOM Killer 会立即介入。建议只在确认实际内存用量后再缩减。
  2. cgroup v1 限制:内存的 In-Place 调整在 cgroup v1 上行为存在差异,强烈建议升级到 cgroup v2(v1.25+ 默认启用)。
  3. QoS 类不变:调整不能改变 Pod 的 QoS 类别(Guaranteed/Burstable/BestEffort),若调整后 requests == limits 但原来不是,QoS 类仍维持原状。
  4. Deployment/StatefulSet 支持:通过更新 Pod Template 中的资源配置,Deployment 控制器默认仍会触发滚动更新。若要利用 In-Place,需通过直接 patch Pod(适用于有状态场景)或等待 workload controller 对该特性的原生支持。

Sidecar Containers(GA)
#

背景与痛点
#

在 v1.33 之前,“sidecar 模式"只是社区约定,在实现层面上 sidecar 和普通 initContainer 没有区别。这导致了两个经典问题:

  1. 启动顺序:sidecar(如日志采集器、服务网格代理)需要先于主容器启动,但 initContainer 必须执行完成才能启动下一个,无法实现"先启动但保持运行”。
  2. 优雅退出:Job 场景中,sidecar 不知道主容器何时完成,导致 Job 永远无法 Complete(Istio envoy sidecar 注入 Job 的经典问题)。

功能说明
#

v1.28 引入、v1.33 GA 的原生 Sidecar 通过在 initContainers 中新增 restartPolicy: Always 字段实现:

  • 原生启动顺序restartPolicy: Always 的 initContainer 会在普通 initContainer 之后、主容器之前启动,且不等待其"完成"(因为它一直运行)
  • 优雅退出:所有普通容器(主容器)退出后,sidecar 才会收到 SIGTERM
  • 探针支持:原生 sidecar 支持 startupProbe,下一个 initContainer 或主容器要等 sidecar 的 startupProbe 通过才启动

完整配置示例
#

场景一:日志采集 sidecar(确保采集器先于业务启动)

apiVersion: v1
kind: Pod
metadata:
  name: app-with-logging
  namespace: production
spec:
  initContainers:
  # 原生 sidecar:在主容器之前启动,与主容器同生命周期
  - name: log-collector
    image: fluent/fluent-bit:3.0
    restartPolicy: Always          # 这是关键字段
    volumeMounts:
    - name: log-volume
      mountPath: /logs
    - name: fluent-bit-config
      mountPath: /fluent-bit/etc
    startupProbe:
      httpGet:
        path: /api/v1/health
        port: 2020
      initialDelaySeconds: 3
      periodSeconds: 5
      failureThreshold: 10
  containers:
  - name: app
    image: myapp:v2.0
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/app
  volumes:
  - name: log-volume
    emptyDir: {}
  - name: fluent-bit-config
    configMap:
      name: fluent-bit-config

场景二:Job 中的 Istio sidecar 问题修复

之前 Istio 注入 Job 后,envoy sidecar 不会退出导致 Job 卡住。使用原生 sidecar 后:

apiVersion: batch/v1
kind: Job
metadata:
  name: data-migration
spec:
  template:
    spec:
      initContainers:
      - name: istio-proxy
        image: istio/proxyv2:1.21.0
        restartPolicy: Always
        args: ["proxy", "sidecar"]
        env:
        - name: ISTIO_META_WORKLOAD_NAME
          value: data-migration
      containers:
      - name: migrator
        image: myapp/migrator:v1.0
        command: ["./migrate.sh"]
      restartPolicy: Never

Job 的主容器 migrator 完成后,istio-proxy sidecar 会自动收到终止信号,Job 正常进入 Complete 状态。

注意事项
#

  1. 与 Istio/Linkerd 自动注入的兼容性:服务网格的 Mutating Webhook 可能还在注入老式 sidecar(普通 container),需确认服务网格版本是否已切换到原生 sidecar 注入(Istio 1.21+ 支持)。
  2. 资源计算:原生 sidecar 的资源会计入 Pod 总资源,影响调度决策和 LimitRange 检查。
  3. 优先级:多个原生 sidecar 按定义顺序依次启动,每个 sidecar 的 startupProbe 通过后才启动下一个。

Job 改进:Backoff Limit Per Index 与 Pod Failure Policy
#

Backoff Limit Per Index(GA)
#

Indexed Job 中,每个 index(任务分片)现在可以有独立的失败重试次数,而不是整个 Job 共用一个 backoffLimit

apiVersion: batch/v1
kind: Job
metadata:
  name: batch-processor
spec:
  completions: 100
  parallelism: 10
  completionMode: Indexed
  backoffLimitPerIndex: 3    # 每个 index 最多重试 3 次
  maxFailedIndexes: 10       # 超过 10 个 index 失败后,整个 Job 失败
  template:
    spec:
      containers:
      - name: processor
        image: myapp/processor:v1
        env:
        - name: JOB_COMPLETION_INDEX
          valueFrom:
            fieldRef:
              fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
      restartPolicy: Never

使用场景:大规模批处理(ML 训练数据预处理、报表生成等),部分任务因数据问题必然失败,不应该因为少数分片失败导致整个 Job 重试风暴。

Pod Failure Policy(GA)
#

精细控制 Pod 失败后的处理行为,支持基于退出码和容器状态进行规则匹配:

apiVersion: batch/v1
kind: Job
metadata:
  name: ml-training
spec:
  backoffLimit: 6
  podFailurePolicy:
    rules:
    # OOM 导致的失败:立即终止整个 Job,不重试(资源不足)
    - action: FailJob
      onPodConditions:
      - type: DisruptionTarget
    # 退出码 42 表示数据错误:忽略该次失败,不计入 backoffLimit
    - action: Ignore
      onExitCodes:
        containerName: trainer
        operator: In
        values: [42]
    # 退出码 1:正常计入重试
    - action: Count
      onExitCodes:
        containerName: trainer
        operator: In
        values: [1]
  template:
    spec:
      containers:
      - name: trainer
        image: myapp/trainer:v1
      restartPolicy: Never

Pod Scheduling Readiness(GA)
#

功能说明
#

通过 schedulingGates 字段,可以阻止 Pod 进入调度队列,直到外部控制器移除所有 gate。这对以下场景非常有价值:

  • 依赖预热:等待 ConfigMap/Secret 准备好再调度(避免调度后启动失败)
  • 配额预留:先占位,待外部资源(GPU、特殊硬件)确认可用后再正式调度
  • 批量调度协调:多个 Pod 协调后一起进入调度队列,避免碎片化占用节点

配置示例
#

apiVersion: v1
kind: Pod
metadata:
  name: gpu-workload
  namespace: ml-team
spec:
  schedulingGates:
  - name: "example.com/gpu-quota-reserved"   # 自定义 gate 名称
  - name: "example.com/dataset-ready"
  containers:
  - name: trainer
    image: pytorch/pytorch:2.2
    resources:
      limits:
        nvidia.com/gpu: "4"

外部控制器确认资源就绪后,移除 gate:

# 移除单个 gate
kubectl patch pod gpu-workload -n ml-team --type=json -p='[
  {
    "op": "remove",
    "path": "/spec/schedulingGates/0"
  }
]'

# 当所有 gate 都被移除后,Pod 才进入调度队列

注意schedulingGates 只能移除,不能新增(Pod 创建后)。gate 名称需符合域名格式,推荐使用公司域名前缀。


Volume Groups Snapshot(Beta)
#

功能说明
#

跨多个 PVC 的原子快照。典型场景:数据库的数据盘和日志盘是两个 PVC,单独快照会有时间差导致数据不一致;VolumeGroupSnapshot 保证多个 PVC 在同一时刻被快照。

apiVersion: groupsnapshot.storage.k8s.io/v1beta1
kind: VolumeGroupSnapshot
metadata:
  name: mysql-consistent-snapshot
  namespace: production
spec:
  volumeGroupSnapshotClassName: csi-aws-vgs-class
  source:
    selector:
      matchLabels:
        app: mysql
        snapshot-group: data-and-log   # 选择同一组的多个 PVC
---
# 对应的 PVC 需要打上相同标签
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
  labels:
    app: mysql
    snapshot-group: data-and-log
spec:
  accessModes: [ReadWriteOnce]
  resources:
    requests:
      storage: 100Gi
  storageClassName: gp3-encrypted

当前限制:需要 CSI 驱动支持 CREATE_VOLUME_GROUP_SNAPSHOT 能力,AWS EBS CSI Driver v1.27+、GCE PD CSI Driver v1.12+ 已支持。


KMS v2 GA:更安全的 etcd 数据加密
#

背景
#

KMS v1 使用同步 gRPC 调用,每个加密操作都是阻塞的,在高写入负载下会成为 apiserver 的性能瓶颈。KMS v2 引入了:

  • 异步加密:通过 WatchKeys 流式 RPC 接收密钥更新通知,无需每次请求都调用 KMS
  • 密钥缓存:本地缓存 DEK(Data Encryption Key),性能大幅提升
  • 密钥轮换:支持自动密钥轮换,无需重启 apiserver

配置示例(使用 AWS KMS)
#

/etc/kubernetes/encryption-config.yaml

apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets
    - configmaps
    providers:
    - kms:
        apiVersion: v2          # 使用 KMS v2
        name: aws-kms-provider
        endpoint: unix:///var/run/kmsplugin/socket.sock
        timeout: 3s
        cachesize: 1000         # 本地缓存 DEK 数量
    - identity: {}              # 兜底:未加密读取(用于迁移)

kube-apiserver 启动参数:

- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml
- --encryption-provider-config-automatic-reload=true  # 支持热重载配置

迁移步骤(v1 → v2)

# 1. 先部署支持 v2 的 KMS plugin(兼容 v2 协议)
# 2. 更新 encryption-config,apiVersion 改为 v2
# 3. 执行 Secret 重加密(用新密钥重写所有 Secret)
kubectl get secrets --all-namespaces -o json | \
  kubectl replace -f -

# 4. 验证加密状态
kubectl get --raw='/healthz/etcd-encryption'

Node Memory Swap 改进:LimitedSwap 策略
#

v1.33 对 swap 支持进一步完善,LimitedSwap 策略正式稳定:

  • BestEffort Pod:禁止使用 swap
  • Burstable Pod:允许按比例使用 swap(swap_limit = memory_limit * swapRatio
  • Guaranteed Pod:默认禁止(可通过注解开启)

节点配置(kubelet):

# /etc/kubernetes/kubelet-config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
memorySwap:
  swapBehavior: LimitedSwap
featureGates:
  NodeSwap: true

使用场景:内存敏感但允许偶发 swap 的批处理任务,可以减少 OOM Kill 频率,但会带来性能波动。生产数据库节点不建议开启


Structured Authorization Configuration(GA)
#

功能说明
#

替代单一的 --authorization-mode 参数,支持通过配置文件定义多阶段授权链,每个阶段可以是:

  • NodeRBAC:内置授权器
  • Webhook:外部 webhook(支持配置超时、缓存、失败策略)

并且支持 CEL 表达式进行请求预过滤,减少不必要的 webhook 调用。

配置示例
#

/etc/kubernetes/authz-config.yaml

apiVersion: apiserver.config.k8s.io/v1alpha1
kind: AuthorizationConfiguration
authorizers:
  # 第一步:节点授权(kubelet 访问自己节点的资源)
  - type: Node
    name: node

  # 第二步:RBAC(标准权限检查)
  - type: RBAC
    name: rbac

  # 第三步:外部 OPA webhook(仅对特定资源调用)
  - type: Webhook
    name: opa-authz
    webhook:
      timeout: 3s
      failurePolicy: Deny          # webhook 不可用时拒绝请求
      matchConditions:
        # CEL 过滤:只有操作 secrets 或 rolebindings 才调用 OPA
        - expression: >
            request.resourceAttributes.resource in ['secrets', 'rolebindings']
      connectionInfo:
        type: KubeConfigFile
        kubeConfigFile: /etc/kubernetes/opa-authz-kubeconfig.yaml
      authorizedTTL: 5m            # 授权结果缓存 5 分钟
      unauthorizedTTL: 30s

kube-apiserver 启动参数:

- --authorization-config=/etc/kubernetes/authz-config.yaml
# 移除旧参数
# --authorization-mode=Node,RBAC  (由配置文件替代)

迁移注意--authorization-config--authorization-mode 互斥,切换时需同步修改启动参数。


升级到 v1.33 的注意事项
#

API 废弃与移除
#

API废弃版本移除版本替代
flowcontrol.apiserver.k8s.io/v1beta2v1.29v1.33v1
autoscaling/v2beta2 HPAv1.26v1.33autoscaling/v2

升级前必做检查

# 检查集群中是否还在使用废弃 API
kubectl get --raw /metrics | grep apiserver_requested_deprecated_apis

# 使用 pluto 扫描 YAML 文件
pluto detect-files -d ./k8s-manifests --target-versions k8s=v1.33.0

# 使用 kubent(kube-no-trouble)
kubent --target-version 1.33

升级路径建议
#

# 1. 备份 etcd
ETCDCTL_API=3 etcdctl snapshot save /backup/etcd-$(date +%Y%m%d).db

# 2. 升级 control plane(以 kubeadm 为例)
kubeadm upgrade plan v1.33.0
kubeadm upgrade apply v1.33.0

# 3. 逐节点 drain + 升级 kubelet/kubectl
kubectl drain node-01 --ignore-daemonsets --delete-emptydir-data
apt-get install -y kubelet=1.33.0-* kubectl=1.33.0-*
systemctl restart kubelet
kubectl uncordon node-01

# 4. 验证集群健康
kubectl get nodes
kubectl get pods -A | grep -v Running | grep -v Completed

Feature Gate 变更
#

v1.33 中以下 Feature Gate 已锁定为 true(无法关闭):

  • InPlacePodVerticalScaling
  • SidecarContainers
  • PodSchedulingReadiness
  • KMSv2
  • StructuredAuthorizationConfiguration

如果之前通过 Feature Gate 禁用过这些特性,升级后需要相应更新应用逻辑。


总结
#

v1.33 里我觉得生产最值得先用的两个:Sidecar Containers(专治 Job + sidecar 那种永远退不掉的问题)和 In-Place Pod Vertical Scaling(配合 VPA 不用再滚 Pod)。KMS v2 和 Structured AuthZ 可以在安全集群配套跟进,Scheduling Gates 目前主要是平台团队会用到。

Wenzhuo Huang
作者
Wenzhuo Huang
搞运维的工程师,写代码的运维人。专注 Kubernetes、AWS、GitOps 与基础设施可靠性。这个博客既是我的技术笔记本,也是我踩过的坑的受害者档案。

相关文章

Kubernetes 核心架构全景

·2451 字·12 分钟
深入理解 Kubernetes 控制面与工作节点各组件的职责与交互关系,结合生产环境实际经验,梳理核心资源对象与调度原理。

AWS EKS 实战指南

·877 字·5 分钟
覆盖 EKS 核心架构、eksctl/aws cli 常用操作、IRSA 原理与配置、VPC CNI 网络限制、升级流程及常见故障排查。