当 Kubernetes 集群中的数据库 Pod 意外重启时,存储在本地磁盘的数据会随容器消失 —— 这正是云原生存储要解决的核心问题。容器的临时性要求存储必须与计算分离,而不同应用对存储的需求千差万别:数据库需要强一致性,日志收集需要高吞吐,静态资源需要共享访问。Ceph 和 NFS 作为两种主流存储方案,在 Kubernetes 环境中各有适用场景。本文通过实战配置,解析如何为不同业务场景选择和部署合适的存储方案。

一、云原生存储的核心需求

容器化应用对存储的需求与传统虚拟机有显著差异:

  • 持久化:容器销毁后数据不丢失,如数据库文件、用户上传内容
  • 可扩展性:存储容量能随业务增长动态扩展,无需停机
  • 访问模式:支持单 Pod 独占、多 Pod 共享、跨节点访问等多种模式
  • 性能适配:从低延迟块存储到高吞吐对象存储的全场景覆盖
  • 自动化管理:能通过 Kubernetes API 自动创建、挂载和回收

Kubernetes 通过 PV(PersistentVolume)和 PVC(PersistentVolumeClaim)抽象存储层,使应用无需关心底层存储细节。典型的存储使用流程是:

  1. 管理员创建 PV,定义实际存储资源
  2. 开发人员创建 PVC,声明应用所需的存储规格
  3. Pod 通过 PVC 使用存储,实现存储与应用的解耦

二、NFS:简单共享存储的 Kubernetes 实践

NFS(网络文件系统)是最成熟的文件共享方案,配置简单,适合中小规模的文件共享场景。

基础部署与 PV 配置

在 Kubernetes 中使用 NFS 需要先部署 NFS 服务器(可在集群外或作为 Pod 运行),然后创建对应的 PV:

# nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-shared-pv
spec:
capacity:  
storage: 100Gi  # 存储容量 
accessModes: 
- ReadWriteMany  # 支持多节点读写
persistentVolumeReclaimPolicy: Retain  # 回收策略:保留数据 
storageClassName: nfs-shared 
nfs:   
server: 192.168.1.100  # NFS服务器地址  
path: /exports/k8s/shared  # NFS共享路径  
readOnly: false

创建 PVC 声明存储需求:

# nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-shared-storage 
namespace: default
spec:  
accessModes:  
- ReadWriteMany 
resources:  
requests:    
storage: 50Gi  # 请求50Gi存储 
storageClassName: nfs-shared

在 Deployment 中使用 PVC:

# nfs-app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:  name: file-processing-app
spec:  replicas: 3  # 多副本共享存储 
template:   
spec: 
containers:    
- name: processor    
image: file-processor:v1.2  
volumeMounts:      
- name: shared-data    
mountPath: /app/data  # 容器内挂载路径   
volumes:     
- name: shared-data   
persistentVolumeClaim:   
claimName: app-shared-storage  # 引用PVC

这种配置适合需要多副本共享文件的场景,如:

  • 日志收集服务(多个 Pod 写入同一日志目录)
  • 静态资源服务(多个前端 Pod 共享 HTML/CSS 文件)
  • 协作编辑工具(多节点访问同一文档库)

动态供给与安全优化

对于大规模使用,可部署 NFS-Client Provisioner 实现动态 PV 供给:

# nfs-provisioner-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata: 
name: nfs-client-provisioner 
namespace: kube-system
spec:  
replicas: 1 
selector: 
matchLabels:   
app: nfs-client-provisioner  
template:  
spec:    
serviceAccountName: nfs-provisioner   
containers:    
- name: nfs-client-provisioner 
image: k8s.gcr.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2    
volumeMounts:      
- name: nfs-client-root      
mountPath: /persistentvolumes  
env:     
- name: PROVISIONER_NAME       
value: example.com/nfs   
- name: NFS_SERVER       
value: 192.168.1.100        
- name: NFS_PATH       
value: /exports/k8s/dynamic   
volumes:    
- name: nfs-client-root      
nfs:  
server: 192.168.1.100    
path: /exports/k8s/dynamic

创建 StorageClass 支持动态供给:

# nfs-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: 
name: nfs-dynamic
provisioner: example.com/nfs
parameters: 
archiveOnDelete: "false"  # 删除PVC时不归档数据
reclaimPolicy: Delete  # 自动删除对应PV

NFS 在 Kubernetes 中的使用建议:

  • 适合中小规模部署,单 NFS 服务器可能成为瓶颈
  • 关键数据建议开启 NFS 服务器的冗余备份
  • 避免在高 IO 场景使用(如数据库),性能不如块存储
  • 生产环境应配置 NFS 访问控制(如基于 IP 的权限限制)

三、Ceph:企业级分布式存储方案

Ceph 是开源的分布式存储系统,能同时提供块存储、文件存储和对象存储,适合大规模、高可用的存储需求。

Ceph 集群与 RBD 块存储

Ceph 通过 RBD(RADOS Block Device)提供块存储,适合需要低延迟的应用(如数据库)。在 Kubernetes 中使用 Ceph RBD 需要先部署 Ceph 集群,然后配置 RBD Provisioner。

创建 StorageClass 支持动态供给:

# ceph-rbd-sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata: 
name: ceph-rbd
provisioner: rbd.csi.ceph.com
parameters: 
clusterID: ceph-cluster-id  # Ceph集群ID  
pool: k8s-rbd-pool  # Ceph存储池名称 
imageFeatures: layering  # 启用分层特性
csi.storage.k8s.io/provisioner-secret-name: ceph-admin-secret 
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph 
csi.storage.k8s.io/node-stage-secret-name: ceph-admin-secret 
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: Delete  # 删除PVC时自动删除RBD镜像
allowVolumeExpansion: true  # 支持在线扩容

数据库应用使用 Ceph RBD 存储:

# postgres-deployment.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:  name: postgres-cluster
spec:  
serviceName: postgres 
replicas: 1  
template:   
spec:   
containers:  
- name: postgres   
image: postgres:14      
env:       
- name: POSTGRES_PASSWORD   
valueFrom:         
secretKeyRef:            
name: postgres-secrets            
key: password     
volumeMounts:    
- name: data         
mountPath: /var/lib/postgresql/data
volumeClaimTemplates: 
- metadata:  
name: data   
spec:    
accessModes: [ "ReadWriteOnce" ]  # 单节点读写  
storageClassName: "ceph-rbd"   
resources:    
requests:     
storage: 50Gi

CephFS 文件存储

CephFS 提供分布式文件系统,支持多节点共享,性能优于 NFS,适合大规模文件共享:

# ceph-fs-sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:  
name: ceph-fs
provisioner: cephfs.csi.ceph.com
parameters: 
clusterID: ceph-cluster-id 
fsName: k8s-fs  # CephFS文件系统名称 
pool: k8s-fs-data  # 数据存储池  
csi.storage.k8s.io/provisioner-secret-name: ceph-admin-secret 
csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph 
csi.storage.k8s.io/node-stage-secret-name: ceph-admin-secret  
csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
reclaimPolicy: DeleteallowVolumeExpansion: true

媒体处理应用使用 CephFS:

# media-processor.yaml
apiVersion: apps/v1
kind: Deployment
metadata: 
name: media-processor
spec: 
replicas: 5  
template: 
spec:     
containers:   
- name: processor
image: media-encoder:v2.1    
volumeMounts:      
- name: media-files     
mountPath: /data/media 
volumes: 
- name: media-files  
persistentVolumeClaim:   
claimName: media-storage---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: media-storage
spec:
accessModes: 
- ReadWriteMany  # 多节点读写  
storageClassName: ceph-fs
resources:   
requests:     
storage: 500Gi

Ceph 对象存储

Ceph 通过 RGW(RADOS Gateway)提供 S3 兼容的对象存储,适合存储大量非结构化数据:

# minio-gateway.yaml (使用MinIO作为Ceph RGW的S3网关)
apiVersion: apps/v1
kind: Deployment
metadata: 
name: minio-ceph-gateway
spec: 
replicas: 1 
template:  
spec:      
containers:   
- name: minio       
image: minio/minio     
args: ["gateway", "s3", "http://rook-ceph-rgw-my-store.rook-ceph.svc"]   
env:        
- name: MINIO_ACCESS_KEY      
valueFrom:          
secretKeyRef:           
name: ceph-rgw-credentials       
key: accessKey       
- name: MINIO_SECRET_KEY      
valueFrom:          
secretKeyRef:         
name: ceph-rgw-credentials      
key: secretKey      
ports:      
- containerPort: 9000

应用通过 S3 SDK 访问对象存储:

# 应用代码中使用boto3访问Ceph对象存储
import boto3s3 = boto3.client( 
's3',   
endpoint_url='http://minio-ceph-gateway:9000',  
aws_access_key_id=os.environ['ACCESS_KEY'], 
aws_secret_access_key=os.environ['SECRET_KEY'], 
region_name='us-east-1')
# 上传文件
with open('user-avatar.jpg', 'rb') as f: 
s3.upload_fileobj(f, 'user-uploads', 'avatars/user123.jpg')

四、两种存储方案的对比与选型

特性

NFS

Ceph

部署复杂度

简单,适合快速上手

复杂,需部署分布式集群

可用性

依赖单一服务器,需额外配置高可用

天然分布式,多副本冗余

性能

中等,适合中小规模

高性能,支持从 TB 到 PB 级扩展

功能

仅支持文件存储

支持块存储、文件存储、对象存储

适用场景

小规模文件共享、日志存储

数据库、大规模文件处理、对象存储

运维成本

低,适合小团队

高,需专业存储运维知识

社区支持

成熟稳定

活跃,持续发展

实际选型建议:

  • 开发测试环境:优先选择 NFS,降低部署和维护成本
  • 生产环境中小规模文件共享:NFS 足够满足需求,注意配置 NFS 服务器高可用
  • 数据库和关键业务:使用 Ceph RBD 块存储,确保数据安全和性能
  • 大规模文件处理:选择 CephFS,兼顾性能和扩展性
  • 对象存储需求:Ceph RGW 是开源方案中的最佳选择,或直接使用云厂商对象存储

五、存储性能优化与最佳实践

  1. 访问模式选择
  • 单 Pod 使用:选择 ReadWriteOnce,获得最佳性能
  • 多 Pod 共享读:选择 ReadOnlyMany,适合静态资源
  • 多 Pod 读写:仅在必要时使用 ReadWriteMany,会影响性能
  1. 容量规划
  • 为数据库等核心服务预留 30% 以上的存储空间
  • 配置 StorageClass 支持在线扩容,避免停机
  • 监控存储使用率,设置扩容告警
  1. 性能调优
  • NFS:调整块大小(rsize/wsize),启用异步写入
  • Ceph:根据 workload 调整存储池副本数(通常 3 副本),配置适当的 PG 数量
  1. 数据保护
  • 关键数据定期备份,可使用 Velero 集成 Kubernetes 备份
  • 生产环境 Ceph 建议至少 3 个节点,确保数据冗余
  • 配置存储监控,及时发现磁盘故障
  1. 安全配置
  • NFS:限制客户端 IP,避免未授权访问
  • Ceph:启用认证机制,限制各租户访问范围
  • 敏感数据存储加密(Kubernetes 支持存储加密)

六、云原生存储的未来趋势

随着云原生发展,存储领域呈现几个明显趋势:

  • 存储服务化:通过 Operator 模式简化存储部署和管理,如 Rook 管理 Ceph
  • 容器原生存储:专为容器设计的存储方案,如 Longhorn、OpenEBS
  • 存储与调度协同:Kubernetes 调度器考虑存储位置,减少数据传输
  • 分层存储:自动将热数据放在高性能存储,冷数据迁移到低成本存储

这些趋势使存储更贴合容器化应用的需求,同时降低使用复杂度。

总结

NFS 和 Ceph 在 Kubernetes 环境中各有优势:NFS 以简单取胜,适合中小规模和快速部署场景;Ceph 以功能全面和扩展性强见长,适合企业级生产环境。

选择存储方案的核心是匹配业务需求:不必盲目追求复杂的分布式存储,简单的 NFS 可能更适合团队规模和业务复杂度;而当业务增长到一定规模,Ceph 的分布式架构能提供更好的扩展性和可靠性。

最终,云原生存储的目标是让开发人员无需关心存储细节,通过 PVC 即可获得所需的存储资源,同时保证数据安全、性能和可用性。无论是 NFS 还是 Ceph,能无缝融入 Kubernetes 生态,支撑业务稳定运行,就是合适的选择。