① 背景与问题(解决了什么痛点)

在 Kubernetes 的日常运维中,PersistentVolume(PV)和 PersistentVolumeClaim(PVC)是管理持久化存储的核心资源。然而,在以往的版本中,PV 的 nodeAffinity不可变的,这意味着一旦 PV 被创建并绑定到某个节点,就无法再动态修改其调度策略。

这种限制在以下场景中带来了显著的问题:

场景一:集群扩容或节点变更

当集群中的节点发生变化时,例如新增了高性能 SSD 节点或需要将负载从旧节点迁移至新节点,原有的 PV 可能仍然绑定在旧节点上,导致新的 Pod 无法调度到更合适的节点,影响性能和资源利用率。

场景二:动态调整存储策略

某些应用可能需要根据不同的工作负载类型(如训练、推理、日志等)动态选择不同类型的存储节点。但若 PV 的 nodeAffinity 不可变,就无法灵活地支持这种动态调整。

场景三:故障恢复与维护

当某个节点出现故障或需要维护时,如果 PV 的 nodeAffinity 不可变,Pod 可能无法自动迁移到其他可用节点,导致服务中断。

这些痛点促使 Kubernetes 团队在 v1.35 版本中引入了 Mutable PersistentVolume Node Affinity 功能,允许用户在 PV 创建后动态更新其 nodeAffinity 策略,从而实现更灵活、更智能的存储调度。


② 核心概念/技术原理

什么是 Node Affinity?

Node Affinity 是 Kubernetes 中用于控制 Pod 调度到特定节点的机制。它通过 nodeSelectornodeAffinity 字段来定义节点标签匹配规则。例如,可以指定 Pod 只能运行在带有 storage=ssd 标签的节点上。

在之前的版本中,PV 的 nodeAffinity 是只读的,只能在创建时定义,不能在后续修改。这导致了上述提到的各种问题。

Mutable Node Affinity 的核心变化

在 v1.35 中,Kubernetes 引入了对 PV 的 nodeAffinity 字段的动态更新支持。这意味着:

  • 用户可以在 PV 创建后,通过 kubectl patch 或直接编辑 YAML 文件的方式,修改 nodeAffinity
  • Kubernetes 控制平面会检测到这一变化,并重新评估 PV 的可用性。
  • 如果当前节点不再满足新的 nodeAffinity 条件,系统会尝试将 PVC 绑定到符合新条件的节点上。

注意:该功能目前仍处于 Alpha 阶段,需在 kube-apiserver 和 kube-controller-manager 中启用相应的 Feature Gate。

技术实现方式

  • 在 API Server 中,PV 的 nodeAffinity 字段被标记为可写。
  • 控制器(如 Volume Controller)会监听 PV 的变化,并根据新的 nodeAffinity 重新评估其可用性。
  • 如果 PV 无法满足新的 nodeAffinity,则会触发 PVC 的重新绑定流程。

③ 实战案例/代码示例(重点章节)

场景描述:动态调整存储节点

假设我们有一个 AI 训练平台,其中训练任务需要高 IOPS 的存储,而日志任务则只需要普通存储。我们希望根据任务类型动态调整 PV 的 nodeAffinity。

步骤一:创建初始 PV(使用普通存储节点)
apiVersion: v1
kind: PersistentVolume
metadata:
  name: training-pv
spec:
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: standard
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: storage
          operator: In
          values:
          - standard
  hostPath:
    path: /mnt/data

我们可以用 kubectl apply 命令创建这个 PV:

kubectl apply -f training-pv.yaml

然后查看 PV 状态:

kubectl get pv training-pv

输出结果如下:

NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM   STORAGECLASS   REASON   AGE
training-pv    100Gi      RWO            Retain           Available           standard              1m
步骤二:创建 PVC 并绑定 PV
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: training-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
  volumeName: training-pv

执行命令:

kubectl apply -f training-pvc.yaml

此时 PVC 会被绑定到 training-pv,并运行在带有 storage=standard 标签的节点上。

步骤三:动态更新 PV 的 nodeAffinity

现在,我们希望将该 PV 从 standard 节点迁移到 ssd 节点。我们可以使用 kubectl patch 来更新 PV 的 nodeAffinity。

kubectl patch pv training-pv --type merge -p '{"spec":{"nodeAffinity":{"required":{"nodeSelectorTerms":[{"matchExpressions":[{"key":"storage","operator":"In","values":["ssd"]}]}]}}}'

或者直接编辑 PV:

kubectl edit pv training-pv

在编辑界面中,找到 spec.nodeAffinity 并将其改为:

nodeAffinity:
  required:
    nodeSelectorTerms:
    - matchExpressions:
      - key: storage
        operator: In
        values:
        - ssd

保存并退出。

步骤四:验证 PV 是否成功迁移

再次查看 PV 状态:

kubectl get pv training-pv

输出应显示状态变为 Available,并且可能已不再绑定到原来的 PVC(取决于是否配置了自动重新绑定)。

步骤五:重新绑定 PVC

如果 PVC 未自动重新绑定,可以手动删除 PVC 并重新创建:

kubectl delete pvc training-pvc
kubectl apply -f training-pvc.yaml

此时,PVC 应该被绑定到新的 PV,并运行在 storage=ssd 的节点上。


④ 架构设计/方案对比

传统方案 vs 新特性方案

特性传统方案(v1.34 及之前)新特性(v1.35)
nodeAffinity 是否可变不可变可变
修改方式无法直接修改,需重建 PV支持 kubectl patch 或直接编辑
自动重新绑定支持
使用门槛较高(需删除并重建)较低(直接更新即可)
适用场景静态存储分配动态存储分配、弹性伸缩

架构图说明

以下是 PV nodeAffinity 变化的流程图(使用 Mermaid 语法):

创建 PV

是否设置 nodeAffinity

绑定到特定节点

默认绑定到任意节点

Pod 调度

运行在指定节点

更新 PV nodeAffinity

触发 PVC 重新绑定

绑定到新节点

Pod 重新调度


⑤ 优劣势评估/选型建议

优势分析

  1. 灵活性提升:支持动态调整存储节点,适应更多业务场景。
  2. 减少人工干预:无需删除和重建 PV 即可修改 nodeAffinity。
  3. 增强自动化能力:结合 Operator 或自定义控制器,可实现更智能的存储调度策略。
  4. 提升资源利用率:避免因 nodeAffinity 不可变而导致的资源浪费。

劣势分析

  1. Alpha 功能:目前仍处于 Alpha 阶段,稳定性有待验证。
  2. 兼容性风险:旧版本 Kubernetes 不支持此功能,升级需谨慎。
  3. 配置复杂度增加:需要更细致的 nodeAffinity 策略设计。
  4. 潜在冲突风险:如果多个 PV 共享相同的 nodeAffinity 策略,可能会导致资源争抢。

选型建议

  • 推荐使用场景

    • 需要动态调整存储策略的 AI/ML 平台
    • 多租户环境下的存储隔离
    • 混合云或跨数据中心部署
  • 不推荐使用场景

    • 对稳定性要求极高的生产环境(建议等待 Beta 或 GA 版本)
    • 使用较旧版本的 Kubernetes(低于 v1.35)
    • 不熟悉 nodeAffinity 策略的团队

⑥ 总结与延伸

Kubernetes v1.35 引入的 Mutable PersistentVolume Node Affinity 是一个非常实用的功能,尤其适用于需要动态调整存储策略的场景。通过这项改进,我们可以更灵活地管理存储资源,提高系统的弹性和效率。

虽然该功能仍处于 Alpha 阶段,但在实际测试中已经展现出良好的稳定性和实用性。对于正在构建或优化 AI/ML 平台、云原生架构的企业来说,这是一个值得关注和尝试的新特性。

延伸思考

未来,随着 Kubernetes 生态的不断完善,我们可以期待更多关于存储调度的高级功能,例如:

  • 基于负载的自动调度策略
  • 多级 nodeAffinity 支持
  • 与 CSI 插件的深度集成

如果你正在使用 Kubernetes 进行大规模存储管理,不妨尝试在测试环境中体验这一新特性,并反馈你的使用感受给社区,帮助 Kubernetes 更加完善。


更多推荐