Kubernetes 存储 accessModes 的 4 种模式

Kubernetes 的 accessModes 定义了存储卷(PV)的并发访问策略,核心区别在于:允许多少个节点(或 Pod)同时挂载,以及读写权限。

以下是四种模式的详细使用指南:

一、四种模式对比速查

模式缩写同时挂载范围读写权限
ReadWriteOnceRWO单个节点读写
ReadOnlyManyROX多个节点只读
ReadWriteManyRWX多个节点读写
ReadWriteOncePodRWOP单个 Pod读写

二、逐个详解与使用场景

1. ReadWriteOnce (RWO) - 单节点读写

它允许一个节点上的一个或多个Pod对其进行读写。注意:是"节点"级别而非"Pod"级别。

apiVersion: v1
kind: PersistentVolumeClaim
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: standard-rwo  # 如云硬盘

关键特性:

  • 同一 Node 上的多个 Pod 可以同时读写。
  • 不同 Node 的 Pod 无法挂载(会处于 Pending 状态)。

适用场景:

  • 数据库单机版:单实例数据库:绝大多数数据库(如MySQL, PostgreSQL, MongoDB)要求存储卷只能有一个写入者,否则会引起数据损坏。RWO完美地满足了这一要求。
  • StatefulSet 单副本:任何需要持久化存储,且不需要在多个节点间共享数据的应用,比如Kafka、Elasticsearch的一个数据节点。
  • 临时缓存:Redis 单机持久化。

限制示例:

# 如果 Deployment 副本数 > 1,且使用 RWO:
replicas: 3
# 结果:只有调度到已挂载节点的 Pod 能运行,其他的会 ContainerCreating 卡住

同一个卷不能被两个不同节点上的Pod同时挂载。如果Deployment的副本数大于1且Pod被调度到不同节点,就会导致挂载失败。

2. ReadOnlyMany (ROX) - 多节点只读

允许多个节点同时挂载,但所有挂载都是只读。适用于数据只需读取,无需改写的场景。

spec:
  accessModes: ["ReadOnlyMany"]

适用场景:

  • 静态资源配置:Web 服务器的静态文件(图片、JS、CSS)。
  • 配置中心:大规模读取的配置文件,需要多 Pod 共享但不可修改。
  • 预训练模型:AI 推理服务加载的只读模型文件。
  • 镜像缓存:Container Registry 的只读存储后端。

实现注意:

  • 通常需要先在存储端准备好数据,Kubernetes 端只读挂载。
  • 不能用于需要写入日志或临时文件的应用。

3. ReadWriteMany (RWX) - 多节点读写

允许多个节点同时读写。真正的共享存储。

spec:
  accessModes: ["ReadWriteMany"]
  storageClassName: nfs-client  # 或 efs-sc、alicloud-nas

适用场景:

  • 文件共享服务:企业网盘、文档协作系统。
  • AI/ML 训练数据:多 Worker 节点并发读取训练集。
  • 日志汇聚:Fluentd/Filebeat 多节点写入,Logstash 读取。
  • CI/CD 缓存:Jenkins 分布式构建共享 Maven/Gradle 缓存。
  • 多媒体处理:视频转码任务分布式处理共享素材库。

数据一致性警告:

  • 需要应用自身处理文件锁(NFS 是建议性锁)。
  • 不适合数据库(MySQL 等需要底层块设备随机写)。

4. ReadWriteOncePod (RWOP) - 单 Pod 独占

Kubernetes 1.29+可用,保证单个 Pod 独占存储,即使同一节点上的其他 Pod 也无法访问。在整个集群中,只有一个Pod可以挂载该卷。

spec:
  accessModes: ["ReadWriteOncePod"]  # 最强限制

适用场景:

  • 严格单实例:防止 Deployment 误配置多副本导致数据损坏
  • License 限制软件:某些商业软件要求存储独占
  • 裸块设备:直接操作块设备(非文件系统)的场景,如 LVM 管理

与 RWO 的关键区别:

场景RWORWOP
同一节点 Pod A 已挂载Pod B 可以挂载Pod B 无法挂载
保证级别节点级Pod 级

三、如何选择?

选择逻辑其实很简单,可以按下面的思路来决策:

  1. 首先,看应用是否需要“写”数据?
    • 只读 -> 选 ReadOnlyMany。
    • 需要写入 -> 进入下一步。
  2. 其次,看应用是否需要“共享”数据?
    • 不需要共享,自己用就行 -> 选 ReadWriteOnce。(这是最常见的场景,比如MySQL)
    • 需要共享给其他Pod -> 进入下一步。
  3. 最后,确认共享时的访问权限。
    • 多个Pod可以同时读写 -> 选 ReadWriteMany。(比如共享文件服务器)
    • 整个集群只允许一个Pod读写,严格避免任何并发 -> 选 ReadWriteOncePod。(比如某个关键的、不支持并发的旧版应用)

四、常见误区与陷阱

误区 1:RWO = 单个 Pod

错误认知:认为 RWO 保证只有一个 Pod 能访问。 实际情况:RWO 是节点级限制。如果两个 Pod 调度到同一 Node,它们都能读写。

解决方案:需要真正单实例时,使用 RWOP 或将 replicas 固定为 1。

误区 2:随意切换 accessMode

PVC 创建后不能修改 accessModes。如需变更,必须:

  1. 删除旧 PVC(注意备份数据)。
  2. 创建新 PVC 指定新模式。
  3. 重新挂载到 Pod。

误区 3:所有存储都支持所有模式

云硬盘(EBS):仅支持 RWO。

NFS:支持 RWO、ROX、RWX(但 RWO 在多节点场景下会调度失败)。

本地存储(Local PV):仅支持 RWO。

误区 4:RWX 适合数据库

绝对禁止:PostgreSQL、MySQL、etcd 等使用 RWX 会导致数据损坏(并发写冲突)。

例外:SQLite 等嵌入式数据库如果应用层处理好锁机制,理论上可以,但极不推荐生产使用。

五、配置示例

场景:WordPress 部署(内容+媒体分离)

# 1. 应用代码(多副本只读)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-code
spec:
  accessModes: ["ReadOnlyMany"]  # 所有 Pod 共享只读代码
  resources:
    requests:
      storage: 1Gi
---
# 2. 用户上传(多副本读写)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wp-uploads
spec:
  accessModes: ["ReadWriteMany"]  # 用户上传图片需要共享
  storageClassName: nfs-client
  resources:
    requests:
      storage: 10Gi
---
# 3. 数据库(单实例独占)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data
spec:
  accessModes: ["ReadWriteOncePod"]  # 严格单实例,防止误扩
  storageClassName: ssd-block
  resources:
    requests:
      storage: 20Gi