Skip to main content

前言

Kubernetes集群中,容器的存储默认是临时的,当Pod重启或删除时,容器内的数据会丢失。对于数据库、日志系统、文件存储等需要持久化数据的应用场景,我们需要使用Kubernetes提供的持久化存储机制。PersistentVolumeClaimPVC)是Kubernetes存储架构中的核心抽象,它将存储的使用者(Pod)和存储的提供者(PersistentVolume)解耦,使得应用开发者无需关心底层存储的具体实现细节。

PVC是什么?

PersistentVolumeClaimPVC)是用户对存储资源的请求声明。它类似于Pod对计算资源(CPU、内存)的请求,但PVC请求的是存储资源。通过PVC,用户可以声明所需的存储大小、访问模式等需求,而无需关心存储的具体实现。

Kubernetes存储架构

Kubernetes的存储系统由三个核心概念组成:

概念说明
PV (PersistentVolume)集群中的一块存储资源,由管理员手动创建或通过StorageClass动态创建。PV是集群级别的资源,独立于Pod的生命周期。
PVC (PersistentVolumeClaim)用户对存储资源的申请。PVC会自动绑定到满足条件的PV上。
StorageClass定义了存储的类别和动态供应的参数,允许用户在创建PVC时自动创建对应的PV

PVC解决了什么问题?

在传统容器部署中,直接使用volume挂载存储存在以下问题:

痛点案例1:存储配置与应用耦合

场景:某团队开发了一个微服务应用,需要在开发、测试、生产环境分别部署。

问题

  • 不同环境使用不同的存储后端(开发用本地存储,测试用NFS,生产用云存储)
  • 每个环境都需要修改Pod配置中的volume定义
  • 应用开发者需要了解每个环境的存储细节
  • 迁移环境时需要大量修改配置文件

解决方案

  • 使用PVC抽象存储需求,应用只声明需要10Gi存储和读写模式
  • 不同环境的集群管理员配置各自的StorageClass
  • 应用配置在各环境保持一致,存储后端由PVC自动适配

痛点案例2:存储资源的复用和管理

场景:运维团队需要管理大量的存储资源,多个应用共享存储系统。

问题

  • 手动为每个应用分配存储空间,管理复杂
  • 存储空间难以复用,删除应用后存储资源闲置
  • 缺乏统一的存储配额和权限管理
  • 存储扩容需要修改每个使用存储的Pod配置

解决方案

  • 使用PV池管理存储资源,支持动态分配和回收
  • 通过PVC的生命周期管理实现存储的自动回收或保留
  • 使用StorageClass实现存储配额、性能等级的分类管理
  • 支持PVC扩容,无需修改Pod配置

痛点案例3:有状态应用的部署

场景:部署MySQL数据库集群,每个实例需要独立的持久化存储。

问题

  • 每个数据库实例需要独立且持久的数据目录
  • Pod重启后必须绑定到原来的存储,避免数据丢失
  • 数据库扩容时需要自动创建新的存储卷
  • 删除数据库实例时需要保留数据以便恢复

解决方案

  • 使用StatefulSet配合volumeClaimTemplates自动为每个副本创建PVC
  • PVCPod名称绑定,保证重启后存储的一致性
  • StorageClassreclaimPolicy设置为Retain保留数据
  • 支持数据库集群的弹性伸缩

PVC基础使用

访问模式

PVC支持以下访问模式(AccessModes):

访问模式缩写说明
ReadWriteOnceRWO卷可以被单个节点以读写方式挂载。最常见,适用于大多数块存储。
ReadOnlyManyROX卷可以被多个节点以只读方式挂载。适用于共享配置文件、静态资源等场景。
ReadWriteManyRWX卷可以被多个节点以读写方式挂载。需要存储系统支持,如NFSCephFS等。
ReadWriteOncePodRWOP卷只能被单个Pod以读写方式挂载(Kubernetes 1.22+特性)。

简单的Pod使用PVC示例

以下是创建PVC并在Pod中使用的基本示例:

1. 创建PersistentVolume

首先创建一个PV(在使用动态供应前,通常需要管理员预先创建):

apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-local-storage
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage # 可选
hostPath:
path: /data/k8s-storage
type: DirectoryOrCreate

2. 创建PersistentVolumeClaim

在被Pod/Deployment使用前,用户需要创建对应的PVC申请存储:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-app-data
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: local-storage

说明:

  • accessModes:必须与可用PV的访问模式匹配
  • resources.requests.storage:请求的存储空间大小
  • storageClassName:指定存储类,如果不指定则使用默认StorageClass

3. 在Pod中使用PVC

创建Pod并挂载PVC

apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
namespace: default
spec:
containers:
- name: app
image: nginx:latest
volumeMounts:
- name: data-volume
mountPath: /usr/share/nginx/html
volumes:
- name: data-volume
persistentVolumeClaim:
claimName: pvc-app-data

4. 验证存储挂载

# 查看PVC状态
kubectl get pvc pvc-app-data

# 输出示例
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
# pvc-app-data Bound pv-local-storage 10Gi RWO local-storage 2m

# 进入Pod验证挂载
kubectl exec -it app-with-storage -- df -h /usr/share/nginx/html

网络存储协议与使用

Kubernetes支持多种网络存储协议,可以将远程存储挂载到Pod中。以下介绍常见的网络存储协议及其使用方式。

NFS协议

NFSNetwork File System)是最常用的网络文件系统协议,支持ReadWriteMany访问模式,允许多个Pod同时读写。

NFS服务端配置

假设你已经有一个NFS服务器nfs.team.local,导出目录为/hpc。如果需要搭建NFS服务器,可以参考以下步骤:

# 在NFS服务器上安装nfs-server(Ubuntu/Debian)
apt-get update
apt-get install -y nfs-kernel-server

# 创建共享目录
mkdir -p /data/nfs-share
chmod 777 /data/nfs-share

# 配置NFS导出
cat >> /etc/exports <<EOF
/data/nfs-share *(rw,sync,no_subtree_check,no_root_squash)
EOF

# 重启NFS服务
exportfs -ra
systemctl restart nfs-kernel-server

直接使用NFS卷

最简单的方式是直接在Pod中定义NFS卷:

apiVersion: v1
kind: Pod
metadata:
name: nfs-pod-direct
spec:
containers:
- name: app
image: nginx:latest
volumeMounts:
- name: nfs-volume
mountPath: /data/hpc
volumes:
- name: nfs-volume
nfs:
server: nfs.team.local
path: /hpc
readOnly: false

通过PV/PVC使用NFS

推荐的方式是通过PVPVC使用NFS存储:

1. 创建NFS PersistentVolume:

提示

类似的mount命令为:

sudo mount -t nfs -o rw,relatime,vers=3,rsize=1048576,wsize=1048576,hard,nolock,proto=tcp nfs.team.local:/hpc /data/hpc
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-hpc
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs-storage
mountOptions:
- vers=3
- rsize=1048576
- wsize=1048576
- hard
- nolock
- proto=tcp
nfs:
server: nfs.team.local
path: /hpc

说明:

  • mountOptions:对应命令mount -o的参数
    • vers=3:使用NFSv3协议
    • rsize=1048576:读缓冲区大小为1MB
    • wsize=1048576:写缓冲区大小为1MB
    • hard:硬挂载,网络中断时会重试
    • nolock:不使用NFS文件锁
    • proto=tcp:使用TCP协议

2. 创建PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs-hpc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 50Gi
storageClassName: nfs-storage

3. 在Deployment中使用:

apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app-with-nfs
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: pvc-nfs-hpc

由于NFS支持ReadWriteMany,这个Deployment3个副本可以同时读写同一个存储卷。

CIFS/SMB协议

CIFSCommon Internet File System)也称为SMBServer Message Block),主要用于Windows文件共享,也可以在Linux系统中使用。

使用CIFS卷示例

apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-cifs-share
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: cifs-storage
mountOptions:
- vers=3.0
- dir_mode=0777
- file_mode=0777
csi:
driver: smb.csi.k8s.io
volumeHandle: smb-server.example.com/share
volumeAttributes:
source: "//smb-server.example.com/share"
nodeStageSecretRef:
name: cifs-secret
namespace: default
---
apiVersion: v1
kind: Secret
metadata:
name: cifs-secret
namespace: default
type: Opaque
stringData:
username: "myuser"
password: "mypassword"

注意:从Kubernetes 1.26开始,内置的CIFS卷插件已被废弃,推荐使用CSI驱动(如csi-driver-smb)。

iSCSI协议

iSCSIInternet Small Computer System Interface)是基于TCP/IP的块存储协议,将SCSI命令封装在IP包中传输。

iSCSI存储示例

apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-iscsi-storage
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: iscsi-storage
iscsi:
targetPortal: 192.168.1.100:3260
iqn: iqn.2021-01.com.example:storage.target01
lun: 0
fsType: ext4
readOnly: false

说明:

  • targetPortaliSCSI TargetIP地址和端口
  • iqniSCSI限定名称,标识存储目标
  • lun:逻辑单元号
  • fsType:文件系统类型

注意:使用iSCSI前,需要在Kubernetes节点上安装iscsi-initiator-utils

# CentOS/RHEL
yum install -y iscsi-initiator-utils

# Ubuntu/Debian
apt-get install -y open-iscsi

网络存储协议对比

协议类型访问模式性能适用场景
NFS文件系统RWX中等共享文件存储、日志收集、静态资源
CIFS/SMB文件系统RWX中等Windows环境、办公文件共享
iSCSI块存储RWO数据库、高性能应用
Ceph RBD块存储RWO云原生存储、大规模集群
CephFS文件系统RWX中高分布式文件存储

StorageClass动态存储供应

StorageClass提供了一种描述存储类别的方式,允许管理员定义不同类型的存储服务。使用StorageClass可以实现存储的动态供应,当用户创建PVC时自动创建对应的PV

StorageClass工作原理

NFS动态存储供应

NFS本身不支持动态供应,需要使用外部供应器(如nfs-subdir-external-provisioner)。

1. 部署NFS Provisioner

apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: kube-system
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
namespace: kube-system
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: nfs.team.local
- name: NFS_PATH
value: /hpc
volumes:
- name: nfs-client-root
nfs:
server: nfs.team.local
path: /hpc

2. 创建StorageClass

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "true"
pathPattern: "${.PVC.namespace}-${.PVC.name}"
mountOptions:
- vers=3
- rsize=1048576
- wsize=1048576
- hard
- nolock
- proto=tcp
reclaimPolicy: Delete
volumeBindingMode: Immediate

说明:

  • provisioner:供应器名称,必须与Deployment中的PROVISIONER_NAME一致
  • parameters.archiveOnDelete:删除PVC时是否归档数据
  • parameters.pathPattern:子目录命名模式
  • reclaimPolicy:回收策略,DeleteRetain
  • volumeBindingMode:绑定模式,Immediate(立即绑定)或WaitForFirstConsumer(等待首次使用)

3. 使用动态供应创建PVC

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nfs-dynamic
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: nfs-client

此时无需手动创建PVnfs-client-provisioner会自动创建。

云存储动态供应

云服务商通常提供了CSI驱动支持动态供应,以阿里云为例:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: alicloud-disk-ssd
provisioner: diskplugin.csi.alibabacloud.com
parameters:
type: cloud_ssd
regionId: cn-hangzhou
zoneId: cn-hangzhou-b
fsType: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer

StorageClass参数详解

参数说明可选值
provisioner存储供应器内置或外部供应器名称
parameters供应器特定参数依供应器而定
reclaimPolicy回收策略Delete(删除)、Retain(保留)
allowVolumeExpansion是否允许扩容truefalse
volumeBindingMode绑定模式ImmediateWaitForFirstConsumer
mountOptions挂载选项文件系统挂载参数

Deployment使用PVC

Deployment适用于无状态应用,所有副本共享同一个PVC(需要存储支持ReadWriteMany)或每个副本使用独立的PVCReadWriteOnce)。

场景1:共享存储(ReadWriteMany)

多个副本共享同一份数据,适合静态资源服务器、日志收集等场景:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 20Gi
storageClassName: nfs-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: web-server
template:
metadata:
labels:
app: web-server
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
volumeMounts:
- name: html-data
mountPath: /usr/share/nginx/html
volumes:
- name: html-data
persistentVolumeClaim:
claimName: shared-pvc

场景2:独立存储(ReadWriteOnce)

每个副本需要独立存储,但使用Deployment管理。需要为每个副本创建独立的PVC

# 需要手动创建多个PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pvc-0
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: local-storage
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-pvc-1
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: local-storage
---
# 使用不同的Deployment分别挂载
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-instance-0
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: myapp
instance: "0"
template:
metadata:
labels:
app: myapp
instance: "0"
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-pvc-0

注意:对于需要独立存储的有状态应用,推荐使用StatefulSet而不是Deployment

StatefulSet使用PVC

StatefulSet专为有状态应用设计,提供了volumeClaimTemplates特性,可以为每个副本自动创建独立的PVC

StatefulSet的存储特性

  • 稳定的存储标识:每个PodPVC名称固定为<volumeClaimTemplate名称>-<StatefulSet名称>-<序号>
  • 顺序创建和删除PodPVC按序号顺序创建
  • 持久化保留:删除StatefulSet时默认不会删除PVC,数据得以保留
  • 扩缩容支持:扩容时自动创建新的PVC,缩容时保留PVC供后续恢复使用

MySQL集群示例

以下是一个使用StatefulSet部署MySQL集群的完整示例:

apiVersion: v1
kind: Service
metadata:
name: mysql
namespace: default
labels:
app: mysql
spec:
ports:
- port: 3306
name: mysql
clusterIP: None
selector:
app: mysql
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
namespace: default
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
name: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "MySecurePassword123"
- name: MYSQL_DATABASE
value: "myapp"
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
subPath: mysql
- name: mysql-conf
mountPath: /etc/mysql/conf.d
volumes:
- name: mysql-conf
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: nfs-client
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
namespace: default
data:
my.cnf: |
[mysqld]
default-storage-engine=INNODB
character-set-server=utf8mb4
max_connections=1000
innodb_buffer_pool_size=1G

部署后会创建3个Pod和3个PVC

  • Podmysql-0mysql-1mysql-2
  • PVCmysql-data-mysql-0mysql-data-mysql-1mysql-data-mysql-2

每个MySQL实例都有独立的持久化存储,即使Pod重启也能保留数据。

Redis集群示例

apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
namespace: default
data:
redis.conf: |
port 6379
cluster-enabled yes
cluster-config-file /data/nodes.conf
cluster-node-timeout 5000
appendonly yes
dir /data
---
apiVersion: v1
kind: Service
metadata:
name: redis-cluster
namespace: default
spec:
ports:
- port: 6379
targetPort: 6379
name: client
- port: 16379
targetPort: 16379
name: gossip
clusterIP: None
selector:
app: redis-cluster
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: redis-cluster
namespace: default
spec:
serviceName: redis-cluster
replicas: 6
selector:
matchLabels:
app: redis-cluster
template:
metadata:
labels:
app: redis-cluster
spec:
containers:
- name: redis
image: redis:7.0-alpine
ports:
- containerPort: 6379
name: client
- containerPort: 16379
name: gossip
command:
- redis-server
args:
- /conf/redis.conf
volumeMounts:
- name: redis-data
mountPath: /data
- name: redis-conf
mountPath: /conf
volumes:
- name: redis-conf
configMap:
name: redis-config
volumeClaimTemplates:
- metadata:
name: redis-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: nfs-client

PostgreSQL集群示例

apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: default
spec:
ports:
- port: 5432
name: postgres
clusterIP: None
selector:
app: postgres
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: default
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:15-alpine
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_PASSWORD
value: "SecurePassword456"
- name: POSTGRES_DB
value: "myapp"
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 1000m
memory: 2Gi
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: nfs-client

存储最佳实践

1. 选择合适的访问模式

  • RWO(ReadWriteOnce):适用于数据库、块存储,单节点读写
  • ROX(ReadOnlyMany):适用于配置文件、静态资源的分发
  • RWX(ReadWriteMany):适用于共享文件系统、多节点协作

2. 合理设置回收策略

  • Retain(保留):用于重要数据,删除PVCPV和数据保留,需要手动清理
  • Delete(删除):用于临时数据或可重建的数据,删除PVC时自动清理PV和底层存储

3. 使用StorageClass分类管理

为不同性能要求的应用创建不同的StorageClass

# 高性能SSD存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: io2
iopsPerGB: "50"
reclaimPolicy: Delete
---
# 标准HDD存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard-hdd
provisioner: kubernetes.io/aws-ebs
parameters:
type: sc1
reclaimPolicy: Delete

4. 启用存储扩容

StorageClass中启用卷扩容:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: expandable-storage
provisioner: kubernetes.io/aws-ebs
allowVolumeExpansion: true

扩容PVC

# 编辑PVC增加storage大小
kubectl edit pvc my-pvc

# 或使用patch命令
kubectl patch pvc my-pvc -p '{"spec":{"resources":{"requests":{"storage":"100Gi"}}}}'

5. 使用volumeBindingMode优化调度

对于拓扑感知的存储(如本地存储、云盘),使用WaitForFirstConsumer模式:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer

这样可以确保PVPod调度到节点后再绑定,避免Pod因存储位置不匹配而无法调度。

6. 监控存储使用情况

# 查看PVC使用情况
kubectl get pvc -A

# 查看PV列表
kubectl get pv

# 查看StorageClass
kubectl get storageclass

# 查看Pod的存储挂载
kubectl describe pod <pod-name>

7. 数据备份策略

对于重要数据,建议:

  • 使用VolumeSnapshot进行定期快照
  • 将数据同步到对象存储(如S3
  • 使用专业备份工具(如Velero

常见问题排查

1. PVC一直处于Pending状态

原因

  • 没有匹配的PV可用
  • StorageClass不存在或配置错误
  • 存储配额已满

排查方法

# 查看PVC详情
kubectl describe pvc <pvc-name>

# 查看事件
kubectl get events --sort-by='.lastTimestamp'

# 检查StorageClass
kubectl get storageclass

2. Pod无法挂载PVC

原因

  • 节点缺少必要的存储客户端(如nfs-commonopen-iscsi
  • 存储服务器网络不通
  • 权限配置错误

排查方法

# 查看Pod事件
kubectl describe pod <pod-name>

# 在节点上测试挂载
mount -t nfs nfs.team.local:/hpc /mnt/test

# 查看kubelet日志
journalctl -u kubelet -f

3. 存储性能问题

优化建议

  • 调整NFSrsizewsize参数
  • 使用SSD替代HDD
  • 启用缓存机制
  • 考虑使用分布式存储系统

4. 删除Namespace时PVC无法删除

原因PVC可能被保护或存在Finalizer

解决方法

# 查看PVC的finalizers
kubectl get pvc <pvc-name> -o yaml | grep finalizers -A 5

# 移除finalizers
kubectl patch pvc <pvc-name> -p '{"metadata":{"finalizers":null}}'

总结

PersistentVolumeClaimPVC)是Kubernetes存储架构的核心抽象,通过将存储的使用和供应解耦,极大地简化了应用的存储管理。本文详细介绍了:

  1. PVC基础概念PVPVCStorageClass三者的关系和作用
  2. 网络存储协议NFSCIFSiSCSI等协议的使用方法和配置示例
  3. 动态存储供应:通过StorageClass实现存储的自动创建和管理
  4. 实际应用场景DeploymentStatefulSet中使用PVC的完整示例
  5. 最佳实践:存储选型、配置优化、监控和故障排查

通过合理使用PVCStorageClass,可以实现灵活、可靠、高效的持久化存储方案,满足各类有状态应用的需求。无论是数据库、缓存、文件系统还是日志存储,Kubernetes的存储系统都能提供良好的支持。