当 Kubernetes 集群中的数据库 Pod 意外重启时,存储在本地磁盘的数据会随容器消失 —— 这正是云原生存储要解决的核心问题。容器的临时性要求存储必须与计算分离,而不同应用对存储的需求千差万别:数据库需要强一致性,日志收集需要高吞吐,静态资源需要共享访问。Ceph 和 NFS 作为两种主流存储方案,在 Kubernetes 环境中各有适用场景。本文通过实战配置,解析如何为不同业务场景选择和部署合适的存储方案。
一、云原生存储的核心需求
容器化应用对存储的需求与传统虚拟机有显著差异:
- 持久化:容器销毁后数据不丢失,如数据库文件、用户上传内容
- 可扩展性:存储容量能随业务增长动态扩展,无需停机
- 访问模式:支持单 Pod 独占、多 Pod 共享、跨节点访问等多种模式
- 性能适配:从低延迟块存储到高吞吐对象存储的全场景覆盖
- 自动化管理:能通过 Kubernetes API 自动创建、挂载和回收
Kubernetes 通过 PV(PersistentVolume)和 PVC(PersistentVolumeClaim)抽象存储层,使应用无需关心底层存储细节。典型的存储使用流程是:
- 管理员创建 PV,定义实际存储资源
- 开发人员创建 PVC,声明应用所需的存储规格
- 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 是开源方案中的最佳选择,或直接使用云厂商对象存储
五、存储性能优化与最佳实践
- 访问模式选择:
- 单 Pod 使用:选择 ReadWriteOnce,获得最佳性能
- 多 Pod 共享读:选择 ReadOnlyMany,适合静态资源
- 多 Pod 读写:仅在必要时使用 ReadWriteMany,会影响性能
- 容量规划:
- 为数据库等核心服务预留 30% 以上的存储空间
- 配置 StorageClass 支持在线扩容,避免停机
- 监控存储使用率,设置扩容告警
- 性能调优:
- NFS:调整块大小(rsize/wsize),启用异步写入
- Ceph:根据 workload 调整存储池副本数(通常 3 副本),配置适当的 PG 数量
- 数据保护:
- 关键数据定期备份,可使用 Velero 集成 Kubernetes 备份
- 生产环境 Ceph 建议至少 3 个节点,确保数据冗余
- 配置存储监控,及时发现磁盘故障
- 安全配置:
- NFS:限制客户端 IP,避免未授权访问
- Ceph:启用认证机制,限制各租户访问范围
- 敏感数据存储加密(Kubernetes 支持存储加密)
六、云原生存储的未来趋势
随着云原生发展,存储领域呈现几个明显趋势:
- 存储服务化:通过 Operator 模式简化存储部署和管理,如 Rook 管理 Ceph
- 容器原生存储:专为容器设计的存储方案,如 Longhorn、OpenEBS
- 存储与调度协同:Kubernetes 调度器考虑存储位置,减少数据传输
- 分层存储:自动将热数据放在高性能存储,冷数据迁移到低成本存储
这些趋势使存储更贴合容器化应用的需求,同时降低使用复杂度。
总结
NFS 和 Ceph 在 Kubernetes 环境中各有优势:NFS 以简单取胜,适合中小规模和快速部署场景;Ceph 以功能全面和扩展性强见长,适合企业级生产环境。
选择存储方案的核心是匹配业务需求:不必盲目追求复杂的分布式存储,简单的 NFS 可能更适合团队规模和业务复杂度;而当业务增长到一定规模,Ceph 的分布式架构能提供更好的扩展性和可靠性。
最终,云原生存储的目标是让开发人员无需关心存储细节,通过 PVC 即可获得所需的存储资源,同时保证数据安全、性能和可用性。无论是 NFS 还是 Ceph,能无缝融入 Kubernetes 生态,支撑业务稳定运行,就是合适的选择。