在Kubernetes中,为Pod提供稳定、可靠的存储是构建健壮应用的关键。Kubernetes的存储模型多样,从简单的临时存储到复杂的动态持久化存储,以满足不同场景下的需求。
1. Kubernetes存储分类

存储主要分为以下几类:
- 临时存储:例如
emptyDir
- 半持久化存储:例如
hostPath
- 持久化存储:
- 私有云存储:如 NFS、Ceph、GlusterFS
- 公有云存储:如 AWS EBS、Google Persistent Disk、Azure Disk
2. emptyDir — 临时存储
① 什么是 emptyDir?
当Pod的存储方案设置为emptyDir时,Pod启动后会在其所在节点上创建一个空卷。Pod内容器产生的数据可以读写此卷。该卷的生命周期与Pod绑定,一旦Pod被删除,这个临时卷及其数据也会被一并销毁。
② emptyDir 的用途
主要用于充当不需要数据持久化的临时存储空间,例如某些缓存或中间计算结果。
③ emptyDir 配置示例
# emptydir.yaml
apiVersion: v1
kind: Namespace
metadata:
name: dev
---
apiVersion: v1
kind: Pod
metadata:
name: test-emptydir
namespace: dev
spec:
containers:
- image: nginx:1.20.0
name: test-emptydir
volumeMounts:
- mountPath: /usr/share/nginx/html # 挂载到容器内的路径
name: cache-volume
volumes:
- name: cache-volume
emptyDir: {} # 指定存储方式为 emptyDir
3. hostPath — 半持久化存储
① 什么是 hostPath?
hostPath类型卷将节点宿主机上的文件或目录映射到Pod内部。其功能类似于Docker的-v目录映射。
关键限制:由于Pod可能在集群节点间漂移,而hostPath卷只能访问特定节点上的路径,当Pod漂移到其他节点时,将无法访问原有数据,因此它只是一种半持久化的存储方式。
② hostPath 用途
- 当容器需要访问Docker守护进程内部结构时,例如映射
/var/lib/docker。
- 在容器中运行
cAdvisor时,映射/dev/cgroups。
③ hostPath 配置示例
# hostpath.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-hostpath
namespace: dev
spec:
containers:
- name: test-hostpath
image: nginx:1.20.0
hostname: test-hostpath
volumeMounts:
- name: test-hostpath-volume # 卷名称
mountPath: /usr/share/nginx/html # 挂载到容器的路径
volumes:
- name: test-hostpath-volume
hostPath:
path: /data # 宿主机节点上的目录路径
type: DirectoryOrCreate # 路径类型,如果不存在则创建目录
参数说明:
spec.volumes: 定义挂载到宿主机的目录。

hostPath.type 枚举值:

containers.volumeMounts: 定义挂载到Pod内容器的路径。

4. PV 和 PVC 概念
emptyDir和HostPath都无法解决节点宕机或Pod在其它节点重建时的数据持久化问题。解决方案是使用集群外部的独立存储服务,并通过PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 机制进行管理。
① PV 是什么?
PV是集群中的一块独立存储资源,由管理员预先创建。它抽象了底层存储细节(如NFS、Ceph、云硬盘),并定义了容量、访问模式等属性。PV的生命周期独立于Pod。
PV支持的后端存储类型非常丰富,包括Ceph、GlusterFS、各种公有云块存储(AWS EBS, GCE PD, Azure Disk)、iSCSI以及本地存储(Local)等。
② PVC 是什么?
PVC是用户(或Pod)对存储资源的声明。它指定了所需的存储大小和访问模式,而不关心底层具体实现。Kubernetes会为PVC自动绑定一个符合条件的PV。PVC实现了存储消费与供给的解耦,是现代云原生架构中的重要概念。
5. PV/PVC 结合 NFS 实战(持久化存储)
① PV 与 PVC 的关系
使用持久化存储时,Pod通过PVC申请存储,PVC会与一个合适的PV进行绑定(一对一绑定)。
创建顺序为:后端存储 -> PV -> PVC -> Pod。

② NFS 服务器搭建
在存储服务器上执行以下运维操作:
# 1. 安装nfs服务
yum -y install nfs-utils rpcbind
# 2. 创建共享目录并授权
mkdir -p /nfs/data/k8s
chmod -R 777 /nfs/data
# 3. 编辑exports文件
vim /etc/exports
# 添加以下内容(生产环境应限制IP并谨慎授权):
/nfs/data *(rw,no_root_squash,sync)
# 4. 使配置生效并启动服务
exportfs -r
systemctl start rpcbind && systemctl enable rpcbind
systemctl start nfs && systemctl enable nfs
# 5. 在本机测试NFS共享
showmount -e localhost
在所有Kubernetes Node节点上安装NFS客户端:
yum -y install nfs-utils rpcbind
③ 定义 PersistentVolume (PV)
# nginx-pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: nginx-pv # PV的名称
spec:
capacity:
storage: 2Gi # PV的容量
accessModes:
- ReadWriteMany # 访问模式:可被多个节点读写
nfs:
path: /nfs/data/ # NFS服务器共享路径
server: 10.0.0.16 # NFS服务器IP地址
④ 定义 PersistentVolumeClaim (PVC)
PVC会根据定义的访问模式和存储大小,自动寻找并绑定符合要求的PV。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
namespace: dev
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi # 申请2G存储空间
⑤ 定义 Pod,使用 PVC
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-pvc
namespace: dev # 必须与PVC所在命名空间一致
spec:
selector:
matchLabels:
app: nginx-pvc
template:
metadata:
labels:
app: nginx-pvc
spec:
containers:
- name: nginx-test-pvc
image: nginx:1.20.0
ports:
- containerPort: 80
volumeMounts:
- name: nginx-persistent-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-persistent-storage
persistentVolumeClaim:
claimName: nginx-pvc # 引用上面定义的PVC
⑥ 应用并查看
kubectl apply -f nginx-pv-demo.yaml
kubectl get pv,pvc -n dev -o wide
kubectl get pods -n dev -o wide
⑦ PV的回收
- 删除Pod和PVC(必须先删Pod):
kubectl delete deploy/nginx-pvc -n dev
kubectl delete pvc/nginx-pvc -n dev
- 查看PV状态:PVC删除后,Kubernetes会自动启动清理Job清除PV数据,随后PV状态恢复为
Available,可供新的PVC申请。
kubectl get pv
⑧ PV回收策略
通过persistentVolumeReclaimPolicy字段设置:
- Recycle:清除数据,自动回收(基础存储如NFS)。
- Retain:保留数据,需要手动清理。
- Delete:删除存储卷(云存储专用)。
6. 使用 PVC 模板自动创建 (VolumeClaimTemplates)
对于有状态应用(如StatefulSet),可以使用volumeClaimTemplates为每个Pod实例自动创建独立的PVC。
① 预先创建多个 PV
首先在NFS服务器上创建多个目录(如v1-v5),然后定义对应的PV资源。
② 在StatefulSet中使用 VolumeClaimTemplates
# pvctemplate.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx-headless"
replicas: 3
selector:
matchLabels:
app: nginx-pvc
template:
metadata:
labels:
app: nginx-pvc
spec:
containers:
- name: nginx
image: nginx:1.20.0
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # PVC模板
- metadata:
name: www
spec:
accessModes: [ "ReadWriteMany" ]
resources:
requests:
storage: 1Gi
应用后,会生成类似www-web-0、www-web-1的PVC,并自动绑定到符合条件的PV。
7. StorageClass:动态卷供应
① 什么是 StorageClass?
StorageClass是PV的自动化创建工具。管理员可以定义不同的存储类别(如高速SSD、标准HDD)。当用户创建PVC并指定storageClassName时,StorageClass会根据PVC需求,自动创建对应的PV及底层存储,极大简化了运维。
② 为什么要使用 StorageClass?
- 简化管理:无需手动预创建大量PV。
- 动态供应:按需自动创建存储资源。
- 抽象存储:用户只需关注存储类别,无需了解后端细节。
③ StorageClass 工作原理

在动态供应模式下,StorageClass 配合 PVC 实现资源的自动绑定与供给。
④ StorageClass 字段说明
- Provisioner (存储制备器):决定使用哪个插件来制备PV。
- 内置:如
kubernetes.io/aws-ebs
- 外部:如
nfs-client-provisioner, csi-provisioner
- reclaimPolicy (回收策略):同上文PV的
Retain或Delete。
- allowVolumeExpansion:是否允许卷扩容。
- volumeBindingMode (卷绑定模式):
Immediate:创建PVC后立即绑定PV。
WaitForFirstConsumer:延迟到Pod调度时再绑定,适用于拓扑受限的存储。
8. NFS StorageClass 实战
① 搭建 NFS 服务器 (同上文步骤②)
② 创建 ServiceAccount 和 RBAC 授权
StorageClass 等资源需要特定权限来管理,因此需创建专用账户并授权。
# sa.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
namespace: default
# rbac.yaml
# 内容较长,主要为 nfs-client-provisioner 账户绑定操作 PV、PVC、StorageClass 等资源的权限
③ 部署 NFS Client Provisioner
Provisioner 是一个Pod,负责对接NFS服务器并动态创建子目录作为PV。
# nfs-client-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner # 使用刚创建的SA
containers:
- name: nfs-client-provisioner
image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: nfs-storage # Provisioner名称,需与StorageClass对应
- name: NFS_SERVER
value: 192.168.1.34 # NFS服务器IP
- name: NFS_PATH
value: /nfs/data/k8s # NFS共享路径
volumes:
- name: nfs-client-root
nfs:
server: 192.168.1.34
path: /nfs/data/k8s
④ 创建 StorageClass
# nfs-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: nfs-storage # 必须与Provisioner中定义的名称一致
parameters:
server: "192.168.1.34"
path: "/nfs/data/k8s"
readOnly: "false"
⑤ 测试使用
- 创建PVC,它将触发StorageClass动态创建PV。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-nfs-pvc
spec:
storageClassName: managed-nfs-storage # 指定使用的StorageClass
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
- 创建Pod并使用该PVC。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
volumes:
- name: my-volume
persistentVolumeClaim:
claimName: my-nfs-pvc
containers:
- name: my-container
image: nginx
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: my-volume
⑧ 实战部署流程总结
- 搭建NFS服务器,提供底层存储。
- 部署NFS Client Provisioner,作为动态存储供应商。
- 创建StorageClass,定义动态供给规则。
- 用户创建PVC(指定StorageClass),触发PV的自动创建与绑定。
- Pod挂载PVC,使用持久化存储。
Pod使用PVC的完整流程:
Pod -> PVC -> StorageClass -> Provisioner -> 在NFS服务器创建目录 -> PV -> 绑定回PVC -> 供Pod使用。

9. 有状态服务 + StorageClass 综合示例
StatefulSet 配合 volumeClaimTemplates 和 StorageClass 是实现有状态应用(如MySQL、Redis)数据持久化的最佳实践。
① 创建 Headless Service
apiVersion: v1
kind: Service
metadata:
name: mystatefulset-sctemplate
namespace: devlop
spec:
clusterIP: None # 无头服务
selector:
app: mysts-sctemp
ports:
- port: 3306
name: mysql-port
② 创建 StatefulSet
关键点在于使用 volumeClaimTemplates 自动为每个Pod实例创建PVC,并指定 storageClassName。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysts-sctemp
namespace: devlop
spec:
serviceName: mystatefulset-sctemplate
replicas: 3
selector:
matchLabels:
app: mysts-sctemp
template:
metadata:
labels:
app: mysts-sctemp
spec:
containers:
- name: mysql-3306
image: mysql:8.0.27
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456789"
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
- name: mysql-log
mountPath: /var/log/mysql
volumeClaimTemplates: # 自动创建PVC的模板
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteMany" ]
storageClassName: managed-nfs-storage # 指定StorageClass
resources:
requests:
storage: 5Gi
- metadata:
name: mysql-log
spec:
accessModes: [ "ReadWriteMany" ]
storageClassName: managed-nfs-storage # 指定StorageClass
resources:
requests:
storage: 10Gi
通过以上配置,每个MySQL Pod都会拥有自己独立的、由StorageClass动态提供的持久化存储卷,非常适合作为数据库等有状态服务的存储方案。