Kubernetes中双Deployment访问Persistent Disk的非NFS实现方案咨询
非NFS方案实现高吞吐量W/R数据流转
针对你的需求,这里提供几个无需NFS的K8s实现方案,从易到难,适合新手逐步尝试:
方案一:Sidecar模式(最推荐新手)
直接给W的StatefulSet添加一个R侧车容器,和W容器共享同一个PVC卷——因为同一个Pod内的容器天然共享挂载的存储卷,完全不用考虑跨Pod访问的问题。
核心思路
- W容器负责写入数据到PVC挂载的目录
- R容器和W容器在同一个Pod里,直接读取该目录的数据,执行移出操作(比如上传到对象存储、同步到远端服务等)
- 用Pod反亲和性确保每个节点只运行一个W Pod,避免单节点资源竞争
配置示例片段
apiVersion: apps/v1 kind: StatefulSet metadata: name: writer spec: serviceName: writer-svc # StatefulSet必填的无头服务 replicas: 3 selector: matchLabels: app: writer template: metadata: labels: app: writer spec: # 反亲和性:同一节点只跑一个writer Pod affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchLabels: app: writer topologyKey: kubernetes.io/hostname containers: # 写入数据的W容器 - name: writer image: your-writer-image:v1 volumeMounts: - name: data mountPath: /data # 这里添加W容器的启动命令、环境变量等 # 移出数据的R侧车容器 - name: remover image: your-remover-image:v1 volumeMounts: - name: data mountPath: /data # 示例:每小时扫描一次旧文件并移出 command: ["/bin/sh", "-c"] args: ["while true; do find /data -type f -mtime +1 -exec your-move-script {} \\;; sleep 3600; done"] # 自动创建PVC的模板,RWO权限 volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: "your-pd-storageclass" # 替换成你的云厂商PD存储类 resources: requests: storage: 100Gi
优缺点
- ✅ 优点:配置简单,无需跨Pod协调,数据访问延迟低,和W Pod生命周期绑定,Pod销毁时可自动收尾
- ❌ 缺点:R容器和W容器资源绑定,若R是批量处理场景,可能存在资源浪费
方案二:DaemonSet模式(独立R组件)
用DaemonSet部署R,让每个节点上的R Pod和W Pod共享同一节点的PVC——K8s的ReadWriteOnce权限是节点级限制,不是Pod级,同一节点内的多个Pod可以挂载同一个RWO的PVC。
核心思路
- W的StatefulSet用反亲和性保证单节点一个Pod,自动创建对应PVC
- R的DaemonSet在每个节点部署一个Pod,直接挂载该节点上W对应的PVC
- 通过PVC标签筛选,让R Pod找到对应节点的PVC
配置步骤
- 给W的PVC打标签:在volumeClaimTemplates里添加固定标签,方便R筛选
volumeClaimTemplates: - metadata: name: data labels: app: writer-data # 统一标签,用于R筛选 spec: accessModes: ["ReadWriteOnce"] storageClassName: "your-pd-storageclass" resources: requests: storage: 100Gi
- 部署R的DaemonSet:用volumeClaimSelector匹配PVC标签,同时利用DaemonSet的节点特性,自动在有W Pod的节点挂载对应PVC
apiVersion: apps/v1 kind: DaemonSet metadata: name: remover spec: selector: matchLabels: app: remover template: metadata: labels: app: remover spec: # 可选:只在有writer Pod的节点运行R nodeSelector: has-writer: "true" # 需提前给运行writer的节点打此标签 containers: - name: remover image: your-remover-image:v1 volumeMounts: - name: data mountPath: /data command: ["/bin/sh", "-c"] args: ["while true; do your-batch-move-command /data; sleep 3600; done"] volumes: - name: data persistentVolumeClaim: claimSelector: matchLabels: app: writer-data
注意事项
- 若同一节点可能存在多个W Pod(虽然你用了反亲和性避免),需给PVC添加节点名标签,让R精准匹配对应节点的PVC(可通过W Pod的init容器自动给PVC打节点标签)
- 需确保W和R的读写操作不冲突,比如避免同时修改同一文件,可通过文件锁或分目录读写实现
优缺点
- ✅ 优点:R组件独立,资源利用率高,适合批量处理节点上的所有数据
- ❌ 缺点:配置稍复杂,需协调PVC与节点的绑定关系
方案三:Job模式(按需批量处理)
如果数据移出不是实时的,而是周期性或一次性的,可以用Job来处理——每个Job绑定一个PVC,调度到PVC所在的节点执行移出操作。
核心思路
- W的StatefulSet创建带标签的PVC
- 当需要移出数据时,创建Job,通过节点亲和性调度到PVC绑定的节点,挂载PVC执行操作
- 可通过CronJob实现周期性执行
配置示例(CronJob)
apiVersion: batch/v1 kind: CronJob metadata: name: data-remover spec: schedule: "0 0 * * *" # 每天凌晨执行 jobTemplate: spec: template: spec: affinity: # 调度到PVC绑定的节点(需提前给PVC添加node-name标签) nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - $(NODE_NAME) # 需通过变量传递节点名 containers: - name: remover image: your-remover-image:v1 volumeMounts: - name: data mountPath: /data command: ["your-move-command", "/data"] volumes: - name: data persistentVolumeClaim: claimName: writer-0 # 针对单个PVC,若要批量需循环创建Job restartPolicy: OnFailure
优缺点
- ✅ 优点:资源按需分配,适合非实时的批量处理场景
- ❌ 缺点:需管理Job的生命周期,批量处理时需额外协调多个Job的创建
关键知识点提醒
K8s的ReadWriteOnce(RWO)权限容易被误解:它限制的是单个节点挂载,不是单个Pod。也就是说,同一节点内的多个Pod可以同时挂载同一个RWO的PVC,这是所有方案成立的核心前提。
内容的提问来源于stack exchange,提问作者pseudoGeek
相关产品推荐
相关产品推荐

