7.1 存储基础概念
7.1.1 Kubernetes存储概述
Kubernetes提供了多种存储解决方案来满足不同的应用需求:
- 临时存储:Pod重启后数据丢失
- 持久化存储:数据在Pod重启后仍然保留
- 共享存储:多个Pod可以同时访问的存储
- 动态存储:根据需求自动创建存储资源
7.1.2 存储类型
# 存储类型分类
apiVersion: v1
kind: ConfigMap
metadata:
name: storage-types
data:
ephemeral: |
- emptyDir
- hostPath (临时使用)
persistent: |
- PersistentVolume (PV)
- PersistentVolumeClaim (PVC)
network: |
- NFS
- Ceph
- GlusterFS
- iSCSI
cloud: |
- AWS EBS
- Azure Disk
- GCE Persistent Disk
7.2 Volume详解
7.2.1 emptyDir
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: cache-volume
mountPath: /cache
- name: sidecar
image: busybox
command: ['sh', '-c', 'while true; do echo $(date) >> /cache/log.txt; sleep 10; done']
volumeMounts:
- name: cache-volume
mountPath: /cache
volumes:
- name: cache-volume
emptyDir:
sizeLimit: 1Gi
medium: Memory # 使用内存作为存储介质
7.2.2 hostPath
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: host-volume
mountPath: /usr/share/nginx/html
volumes:
- name: host-volume
hostPath:
path: /data/nginx
type: DirectoryOrCreate
7.2.3 configMap和secret卷
apiVersion: v1
kind: Pod
metadata:
name: config-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: config-volume
mountPath: /etc/config
- name: secret-volume
mountPath: /etc/secret
readOnly: true
volumes:
- name: config-volume
configMap:
name: app-config
items:
- key: app.properties
path: app.properties
mode: 0644
- name: secret-volume
secret:
secretName: app-secret
defaultMode: 0400
7.3 PersistentVolume (PV)
7.3.1 PV基本概念
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-example
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /data/pv-example
7.3.2 访问模式
# 访问模式说明
apiVersion: v1
kind: ConfigMap
metadata:
name: access-modes
data:
ReadWriteOnce: |
- 简写:RWO
- 只能被单个节点以读写模式挂载
- 最常用的模式
ReadOnlyMany: |
- 简写:ROX
- 可以被多个节点以只读模式挂载
- 适用于共享配置文件
ReadWriteMany: |
- 简写:RWX
- 可以被多个节点以读写模式挂载
- 需要支持的存储系统
ReadWriteOncePod: |
- 简写:RWOP
- 只能被单个Pod以读写模式挂载
- Kubernetes 1.22+
7.3.3 回收策略
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-reclaim-policy
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete # Retain, Delete, Recycle
storageClassName: fast
nfs:
server: nfs-server.example.com
path: /path/to/data
7.4 PersistentVolumeClaim (PVC)
7.4.1 PVC基本使用
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-example
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: manual
selector:
matchLabels:
environment: production
---
apiVersion: v1
kind: Pod
metadata:
name: pvc-pod
spec:
containers:
- name: app
image: nginx
volumeMounts:
- name: storage
mountPath: /usr/share/nginx/html
volumes:
- name: storage
persistentVolumeClaim:
claimName: pvc-example
7.4.2 动态PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: fast-ssd
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-with-storage
spec:
replicas: 1
selector:
matchLabels:
app: storage-app
template:
metadata:
labels:
app: storage-app
spec:
containers:
- name: app
image: postgres:13
env:
- name: POSTGRES_DB
value: mydb
- name: POSTGRES_USER
value: user
- name: POSTGRES_PASSWORD
value: password
volumeMounts:
- name: postgres-storage
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-storage
persistentVolumeClaim:
claimName: dynamic-pvc
7.5 StorageClass
7.5.1 StorageClass基础
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
7.5.2 不同存储提供商的StorageClass
# AWS EBS StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: aws-ebs-gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
---
# Azure Disk StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: azure-disk-premium
provisioner: disk.csi.azure.com
parameters:
skuName: Premium_LRS
cachingmode: ReadOnly
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
---
# GCE Persistent Disk StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gce-pd-ssd
provisioner: pd.csi.storage.gke.io
parameters:
type: pd-ssd
replication-type: regional-pd
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
7.5.3 本地存储StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /mnt/disks/ssd1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- worker-node-1
7.6 CSI (Container Storage Interface)
7.6.1 CSI驱动安装
# CSI驱动示例 - NFS CSI
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: nfs.csi.k8s.io
spec:
attachRequired: false
podInfoOnMount: true
volumeLifecycleModes:
- Persistent
- Ephemeral
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: csi-nfs-node
namespace: kube-system
spec:
selector:
matchLabels:
app: csi-nfs-node
template:
metadata:
labels:
app: csi-nfs-node
spec:
hostNetwork: true
containers:
- name: node-driver-registrar
image: k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.5.0
args:
- --v=2
- --csi-address=/csi/csi.sock
- --kubelet-registration-path=/var/lib/kubelet/plugins/nfs.csi.k8s.io/csi.sock
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: registration-dir
mountPath: /registration
- name: nfs
image: k8s.gcr.io/sig-storage/nfsplugin:v4.1.0
args:
- --nodeid=$(NODE_ID)
- --endpoint=$(CSI_ENDPOINT)
env:
- name: NODE_ID
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: CSI_ENDPOINT
value: unix:///csi/csi.sock
volumeMounts:
- name: plugin-dir
mountPath: /csi
- name: pods-mount-dir
mountPath: /var/lib/kubelet/pods
mountPropagation: Bidirectional
volumes:
- name: plugin-dir
hostPath:
path: /var/lib/kubelet/plugins/nfs.csi.k8s.io
type: DirectoryOrCreate
- name: registration-dir
hostPath:
path: /var/lib/kubelet/plugins_registry
type: Directory
- name: pods-mount-dir
hostPath:
path: /var/lib/kubelet/pods
type: Directory
7.6.2 使用CSI存储
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: nfs-server.example.com
share: /path/to/nfs/share
volumeBindingMode: Immediate
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: nfs-csi
7.7 存储快照
7.7.1 VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: csi-snapclass
driver: ebs.csi.aws.com
deletionPolicy: Delete
parameters:
encrypted: "true"
7.7.2 创建存储快照
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: pvc-snapshot
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: my-pvc
---
# 从快照恢复PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restored-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
dataSource:
name: pvc-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
storageClassName: fast-ssd
7.8 存储管理脚本
7.8.1 存储监控脚本
#!/bin/bash
# storage-monitor.sh
echo "=== 存储资源监控 ==="
echo "\n1. PersistentVolumes状态:"
kubectl get pv -o custom-columns=NAME:.metadata.name,CAPACITY:.spec.capacity.storage,ACCESS:.spec.accessModes,RECLAIM:.spec.persistentVolumeReclaimPolicy,STATUS:.status.phase,CLAIM:.spec.claimRef.name
echo "\n2. PersistentVolumeClaims状态:"
kubectl get pvc --all-namespaces -o custom-columns=NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase,VOLUME:.spec.volumeName,CAPACITY:.status.capacity.storage,ACCESS:.status.accessModes
echo "\n3. StorageClasses:"
kubectl get storageclass -o custom-columns=NAME:.metadata.name,PROVISIONER:.provisioner,RECLAIM:.reclaimPolicy,BINDING:.volumeBindingMode
echo "\n4. 存储使用情况:"
for node in $(kubectl get nodes -o jsonpath='{.items[*].metadata.name}'); do
echo "\n节点: $node"
kubectl describe node $node | grep -A 5 "Allocated resources"
done
echo "\n5. 存储相关事件:"
kubectl get events --all-namespaces --field-selector reason=FailedMount,reason=FailedAttachVolume,reason=VolumeResizeFailed --sort-by='.lastTimestamp'
7.8.2 存储清理脚本
#!/bin/bash
# storage-cleanup.sh
echo "=== 存储资源清理 ==="
# 清理未绑定的PV
echo "\n1. 清理Available状态的PV:"
kubectl get pv --no-headers | grep Available | awk '{print $1}' | while read pv; do
echo "删除PV: $pv"
kubectl delete pv $pv
done
# 清理失败的PVC
echo "\n2. 清理Lost状态的PVC:"
kubectl get pvc --all-namespaces --no-headers | grep Lost | while read namespace pvc rest; do
echo "删除PVC: $namespace/$pvc"
kubectl delete pvc $pvc -n $namespace
done
# 清理孤儿VolumeAttachment
echo "\n3. 清理孤儿VolumeAttachment:"
kubectl get volumeattachment --no-headers | while read va node rest; do
if ! kubectl get node $node &>/dev/null; then
echo "删除VolumeAttachment: $va (节点 $node 不存在)"
kubectl delete volumeattachment $va
fi
done
echo "\n清理完成!"
7.8.3 存储备份脚本
#!/bin/bash
# storage-backup.sh
NAMESPACE=${1:-default}
BACKUP_DIR="/backup/$(date +%Y%m%d-%H%M%S)"
echo "=== 存储备份 ==="
echo "命名空间: $NAMESPACE"
echo "备份目录: $BACKUP_DIR"
mkdir -p $BACKUP_DIR
# 备份PVC定义
echo "\n1. 备份PVC定义:"
kubectl get pvc -n $NAMESPACE -o yaml > $BACKUP_DIR/pvcs.yaml
# 备份StorageClass定义
echo "2. 备份StorageClass定义:"
kubectl get storageclass -o yaml > $BACKUP_DIR/storageclasses.yaml
# 创建存储快照
echo "3. 创建存储快照:"
kubectl get pvc -n $NAMESPACE --no-headers | while read pvc rest; do
cat <<EOF | kubectl apply -f -
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: backup-$pvc-$(date +%Y%m%d-%H%M%S)
namespace: $NAMESPACE
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: $pvc
EOF
echo "创建快照: backup-$pvc-$(date +%Y%m%d-%H%M%S)"
done
echo "\n备份完成: $BACKUP_DIR"
7.9 存储故障排查
7.9.1 常见存储问题
#!/bin/bash
# storage-troubleshoot.sh
echo "=== 存储故障排查 ==="
# 检查PVC绑定问题
echo "\n1. 检查未绑定的PVC:"
kubectl get pvc --all-namespaces | grep Pending
# 检查存储驱动
echo "\n2. 检查CSI驱动状态:"
kubectl get csidriver
kubectl get csistoragecapacity --all-namespaces
# 检查存储节点
echo "\n3. 检查存储节点状态:"
kubectl get csinode
# 检查存储相关Pod
echo "\n4. 检查存储相关Pod:"
kubectl get pods -n kube-system | grep -E "csi|storage|provisioner"
# 检查存储事件
echo "\n5. 检查存储相关事件:"
kubectl get events --all-namespaces --field-selector reason=FailedMount
kubectl get events --all-namespaces --field-selector reason=FailedAttachVolume
# 检查节点存储容量
echo "\n6. 检查节点存储容量:"
kubectl top nodes
kubectl describe nodes | grep -A 5 "Allocated resources"
7.9.2 存储性能测试
# 存储性能测试Pod
apiVersion: v1
kind: Pod
metadata:
name: storage-benchmark
spec:
containers:
- name: fio
image: ljishen/fio
command:
- fio
- --name=test
- --ioengine=libaio
- --iodepth=64
- --rw=randwrite
- --bs=4k
- --direct=1
- --size=1G
- --numjobs=4
- --runtime=60
- --group_reporting
- --filename=/data/testfile
volumeMounts:
- name: test-volume
mountPath: /data
volumes:
- name: test-volume
persistentVolumeClaim:
claimName: benchmark-pvc
restartPolicy: Never
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: benchmark-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: fast-ssd
7.10 存储最佳实践
7.10.1 存储规划
# 存储规划示例
apiVersion: v1
kind: ConfigMap
metadata:
name: storage-planning
data:
guidelines: |
1. 存储类型选择:
- 数据库: 高IOPS SSD存储
- 日志文件: 标准存储
- 临时文件: emptyDir
- 配置文件: ConfigMap/Secret
2. 容量规划:
- 预留20-30%的增长空间
- 考虑备份和快照需求
- 监控存储使用趋势
3. 性能考虑:
- 选择合适的存储类型
- 配置适当的IOPS和吞吐量
- 考虑网络延迟影响
4. 可用性设计:
- 使用副本和备份
- 跨可用区部署
- 定期测试恢复流程
7.10.2 存储安全
# 存储加密配置
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: encrypted-storage
provisioner: ebs.csi.aws.com
parameters:
type: gp3
encrypted: "true"
kmsKeyId: "arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012"
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
---
# RBAC for storage
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: storage-admin
rules:
- apiGroups: [""]
resources: ["persistentvolumes", "persistentvolumeclaims"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: ["snapshot.storage.k8s.io"]
resources: ["volumesnapshots", "volumesnapshotclasses"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
7.11 本章总结
本章详细介绍了Kubernetes中的持久化存储,主要内容包括:
核心概念
- Volume类型:emptyDir、hostPath、configMap、secret等
- PV/PVC:持久化卷和持久化卷声明的概念和使用
- StorageClass:动态存储供应和存储类配置
- CSI:容器存储接口和第三方存储驱动
存储管理
- 存储监控:监控存储资源使用情况和状态
- 存储备份:创建存储快照和备份策略
- 故障排查:诊断和解决存储相关问题
- 性能优化:存储性能测试和调优
最佳实践
- 存储规划:合理选择存储类型和容量规划
- 安全配置:存储加密和访问控制
- 高可用设计:跨可用区存储和备份策略
- 成本优化:存储资源的合理使用和清理
注意事项
- 选择合适的存储类型和访问模式
- 注意存储的生命周期管理
- 定期备份重要数据
- 监控存储性能和容量使用
下一章我们将学习Kubernetes的网络管理,包括网络策略、服务网格等高级网络功能。