1. 为什么需要持久化存储
在Kubernetes集群中,Pod的生命周期是短暂的。当Pod被删除或重新调度时,其内部存储的数据也会随之消失。这种特性对于无状态应用来说没有问题,但对于数据库、文件存储等有状态应用来说就是灾难性的。
想象一下你正在运行的MySQL数据库,如果因为节点故障导致Pod被重新调度,所有数据都会丢失。这显然是不可接受的场景。持久化存储就是为了解决这个问题而存在的核心功能。
我曾在生产环境中遇到过因为没有正确配置持久化存储,导致重要业务数据丢失的案例。那次事故让我们团队花了整整三天时间从备份恢复数据,期间业务完全停滞。这个惨痛教训让我深刻理解了持久化存储在Kubernetes中的重要性。
2. Kubernetes持久化存储的核心概念
2.1 Volume与PersistentVolume
Kubernetes中的存储抽象主要分为两个层次:
-
Volume:这是Pod级别的存储概念。它定义了Pod如何访问存储,但生命周期与Pod绑定。当Pod消失时,Volume通常也会被清理。
-
PersistentVolume(PV):这是集群级别的存储资源。PV的生命周期独立于Pod,可以由管理员预先配置,或者通过StorageClass动态供给。
yaml复制# 一个简单的PV定义示例
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: "/mnt/data"
2.2 PersistentVolumeClaim(PVC)
PVC是用户对存储资源的"请求"。它定义了应用需要的存储大小和访问模式。Kubernetes会根据PVC的描述找到匹配的PV进行绑定。
yaml复制apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 3Gi
重要提示:PVC请求的存储大小不能超过PV的容量。在实际操作中,我建议预留至少20%的缓冲空间,避免因临时数据增长导致的问题。
2.3 StorageClass
StorageClass定义了"如何"提供存储,而不是"什么"存储。它允许管理员描述他们提供的存储类型,用户无需关心底层细节。
yaml复制apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
replication-type: none
3. 主流持久化存储方案实战
3.1 本地存储方案
3.1.1 hostPath
hostPath是最简单的本地存储方案,直接将节点上的目录挂载到Pod中。
yaml复制apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: Directory
适用场景:
- 开发和测试环境
- 需要访问节点特定文件的场景(如收集节点日志)
注意事项:
- 数据不具备高可用性,节点故障会导致数据丢失
- Pod不能在不同节点间自由调度
- 在生产环境中使用时需要特别小心
3.1.2 local PV
local PV是Kubernetes 1.14后正式GA的特性,相比hostPath更适合生产环境。
yaml复制apiVersion: v1
kind: PersistentVolume
metadata:
name: example-local-pv
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node-1
优势:
- 支持PV的所有特性(如容量声明、访问模式等)
- 通过nodeAffinity确保Pod调度到正确的节点
- 比hostPath更规范,适合生产环境
3.2 网络存储方案
3.2.1 NFS
NFS是常见的网络文件共享协议,配置简单,适合中小规模集群。
yaml复制apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
path: /share
server: 192.168.1.100
部署NFS服务器:
bash复制# 在NFS服务器上执行
sudo apt-get install nfs-kernel-server
sudo mkdir -p /share
sudo chmod 777 /share
echo "/share *(rw,sync,no_subtree_check)" | sudo tee -a /etc/exports
sudo exportfs -a
sudo service nfs-kernel-server start
性能调优建议:
- 对于小文件密集型应用,调整NFS的rsize和wsize参数
- 考虑使用NFSv4,它比NFSv3有更好的性能和特性
- 在高负载环境下,建议使用专业的NAS设备而非自建NFS
3.2.2 Ceph RBD
Ceph是分布式存储系统,RBD(块设备)是其核心组件之一。
yaml复制apiVersion: v1
kind: PersistentVolume
metadata:
name: ceph-rbd-pv
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
rbd:
monitors:
- 10.16.154.78:6789
- 10.16.154.82:6789
- 10.16.154.83:6789
pool: rbd
image: ceph-image
fsType: ext4
readOnly: false
user: admin
keyring: /etc/ceph/ceph.client.admin.keyring
persistentVolumeReclaimPolicy: Delete
storageClassName: ceph-rbd
部署建议:
- 至少使用3个monitor节点确保高可用
- 根据业务需求选择合适的pg_num和pgp_num值
- 考虑使用SSD作为OSD的journal设备提升性能
3.2.3 AWS EBS/GCP PD
云平台提供的块存储服务通常是最简单的选择。
yaml复制apiVersion: v1
kind: PersistentVolume
metadata:
name: gce-pd-pv
spec:
capacity:
storage: 200Gi
accessModes:
- ReadWriteOnce
gcePersistentDisk:
pdName: my-data-disk
fsType: ext4
最佳实践:
- 对于数据库类应用,选择SSD类型的云磁盘
- 定期创建快照备份重要数据
- 考虑使用区域持久化磁盘(Regional PD)提高可用性
3.3 分布式文件系统
3.3.1 CephFS
CephFS是Ceph提供的分布式文件系统,支持ReadWriteMany访问模式。
yaml复制apiVersion: v1
kind: PersistentVolume
metadata:
name: cephfs-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteMany
cephfs:
monitors:
- 10.16.154.78:6789
- 10.16.154.82:6789
- 10.16.154.83:6789
path: /some/path
user: admin
secretRef:
name: ceph-secret
persistentVolumeReclaimPolicy: Retain
storageClassName: cephfs
3.3.2 GlusterFS
GlusterFS是另一个流行的分布式文件系统。
yaml复制apiVersion: v1
kind: PersistentVolume
metadata:
name: glusterfs-pv
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteMany
glusterfs:
endpoints: glusterfs-cluster
path: myvol
readOnly: false
persistentVolumeReclaimPolicy: Retain
4. 动态供给实战
动态供给是生产环境的推荐做法,它允许按需自动创建存储卷。
4.1 配置StorageClass
yaml复制apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-ssd
zones: us-central1-a, us-central1-b
4.2 创建PVC触发自动供给
yaml复制apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast
resources:
requests:
storage: 30Gi
4.3 在Pod中使用动态供给的存储
yaml复制apiVersion: v1
kind: Pod
metadata:
name: app-with-dynamic-storage
spec:
containers:
- name: app
image: nginx
volumeMounts:
- mountPath: "/data"
name: dynamic-storage
volumes:
- name: dynamic-storage
persistentVolumeClaim:
claimName: dynamic-pvc
5. 数据备份与恢复策略
5.1 Velero备份方案
Velero(原Ark)是Kubernetes的流行备份工具。
bash复制# 安装Velero
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.0.0 \
--bucket my-backup-bucket \
--secret-file ./credentials-velero \
--use-volume-snapshots=false \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio:9000
# 创建备份
velero backup create my-backup --include-namespaces=my-ns
# 恢复备份
velero restore create --from-backup my-backup
5.2 存储层快照
大多数现代存储系统都支持快照功能。
yaml复制apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: db-snapshot
spec:
volumeSnapshotClassName: csi-rbd-snapclass
source:
persistentVolumeClaimName: db-pvc
6. 性能优化与问题排查
6.1 存储性能指标监控
yaml复制apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: storage-metrics
labels:
team: infra
spec:
selector:
matchLabels:
app: storage-metrics
endpoints:
- port: metrics
interval: 30s
6.2 常见问题排查
问题1:PVC处于Pending状态
可能原因:
- 没有可用的PV满足PVC请求
- StorageClass配置错误
- 动态供给器出现问题
排查步骤:
bash复制kubectl describe pvc <pvc-name>
kubectl get events --sort-by=.metadata.creationTimestamp
问题2:Pod无法挂载卷
可能原因:
- 节点上没有安装必要的客户端工具
- 网络连接问题
- 认证失败
排查步骤:
bash复制kubectl describe pod <pod-name>
kubectl logs <pod-name> -c <container-name>
ssh <node> dmesg | grep storage
7. 安全最佳实践
- 使用CSI驱动:较新的CSI驱动通常比in-tree插件更安全
- 限制访问:使用RBAC控制谁可以创建PVC
- 加密敏感数据:考虑使用存储层加密或应用层加密
- 定期轮换凭证:特别是对于云存储的访问密钥
yaml复制apiVersion: v1
kind: Secret
metadata:
name: storage-credentials
type: Opaque
data:
username: <base64-encoded>
password: <base64-encoded>