在 Kubernetes 集群中,当 PVC 存储空间不足时,如何进行安全扩容?本文将深入剖析 PVC 扩容的完整流程,并以 QingCloud CSI 为例,带你掌握 offline 扩容的每一个细节。
PVC 扩容流程概览
在开始扩容操作前,我们需要了解 PVC 扩容的三个关键约束条件:
- CSI 驱动程序支持 - 驱动必须支持扩容操作
- 存储类配置 - StorageClass 必须允许扩容
- 扩容模式 - 区分 online 和 offline 扩容模式
一、确认 CSI 驱动支持情况
1.1 检查驱动支持的扩容模式
首先需要确认你使用的 CSI 驱动是否支持卷扩容,以及支持哪种扩容模式:
- Online 扩容:Volume 可以在已挂载到 Pod 时进行扩容,无需停止服务
- Offline 扩容:Volume 必须先卸载(即停止相关 Pod)才能扩容
以 QingCloud CSI 为例,它仅支持 Offline 扩容,这意味着扩容过程中需要暂时停止使用该 PVC 的 Pod。
1.2 查阅官方文档
不同 CSI 驱动的支持情况各异,务必查阅对应云厂商或存储提供商的文档:
csharp
# 查看当前集群中安装的 CSI 驱动
kubectl get csidrivers.storage.k8s.io
# 获取 CSI 驱动的详细信息
kubectl describe csidriver <driver-name>
二、确认 StorageClass 配置
2.1 检查 allowVolumeExpansion 参数
StorageClass 必须显式允许卷扩展才能进行扩容操作:
csharp
# 查看 StorageClass 配置
kubectl get sc qingcloud-sc -o yaml
关键配置字段:
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: qingcloud-sc
# 必须为 true 才能允许扩容
allowVolumeExpansion: true
provisioner: csi-qingcloud
注意 :如果 allowVolumeExpansion为 false或未设置,PVC 将无法扩容。
2.2 创建时配置允许扩容
如果是创建新的 StorageClass,确保包含此参数:
yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: expandable-sc
provisioner: csi-driver.example.com
allowVolumeExpansion: true
parameters:
type: fast
三、Offline 扩容实战步骤
3.1 准备工作负载停用
对于使用 Deployment 或 StatefulSet 的工作负载,需要先缩减副本数为 0:
ini
# 对于 Deployment
kubectl -n <namespace> scale deployment <deployment-name> --replicas=0
# 对于 StatefulSet
kubectl -n <namespace> scale statefulset <statefulset-name> --replicas=0
重要提示:
- 确保业务可以容忍短暂停服
- 在生产环境中,建议在业务低峰期操作
- 对于有状态应用,确保数据已持久化
3.2 修改 PVC 容量
通过编辑 PVC 配置文件来调整存储容量:
csharp
# 编辑 PVC
kubectl edit pvc <pvc-name> -n <namespace>
修改 spec.resources.requests.storage字段:
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-pvc
namespace: app-ns
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
# 从 10Gi 扩容到 100Gi
storage: 100Gi
storageClassName: qingcloud-sc
volumeMode: Filesystem
注意事项:
- 只能扩容,不能缩容
- 确保新容量在存储后端的配额限制内
- 修改后保存退出即可
3.3 监控物理扩容进度
PVC 的物理容量扩容是一个异步过程,可以通过以下命令监控:
arduino
# 实时监控 PVC 状态
kubectl get pvc <pvc-name> -n <namespace> -w
# 或查看详细状态
kubectl get pvc <pvc-name> -n <namespace> -o yaml
扩容过程中的 PVC 状态:
yaml
status:
accessModes:
- ReadWriteOnce
capacity:
storage: 10Gi # 初始容量
conditions:
- lastProbeTime: null
lastTransitionTime: "2023-10-05T09:28:03Z"
# 关键状态:等待文件系统扩容
message: Waiting for user to (re-)start a pod to finish file system resize of
volume on node.
status: "True"
type: FileSystemResizePending
phase: Bound
状态解读:
FileSystemResizePending:物理扩容已完成,等待文件系统扩容- 此时 PVC 显示的容量仍为旧值,这是正常现象
3.4 恢复工作负载
当 PVC 状态出现 FileSystemResizePending时,可以恢复工作负载:
ini
# 恢复 Deployment
kubectl -n <namespace> scale deployment <deployment-name> --replicas=3
# 恢复 StatefulSet
kubectl -n <namespace> scale statefulset <statefulset-name> --replicas=3
Pod 启动时,Kubernetes 会自动完成文件系统的扩容。
3.5 确认扩容完成
验证扩容是否完全成功:
csharp
# 检查 PVC 最终状态
kubectl get pvc <pvc-name> -n <namespace> -o yaml
成功状态示例:
yaml
spec:
resources:
requests:
storage: 100Gi # 请求的容量
storageClassName: qingcloud-sc
status:
capacity:
storage: 100Gi # 实际容量,应该与请求的一致
phase: Bound
查看扩容事件日志:
xml
kubectl describe pvc <pvc-name> -n <namespace>
成功事件示例:
vbnet
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ExternalExpanding 29m volume_expand Ignoring the PVC: didn't find a plugin capable of expanding the volume; waiting for an external controller to process this PVC.
Warning VolumeResizeFailed 28m (x12 over 28m) external-resizer csi-qingcloud resize volume pvc-e78f36e1-bb9c-40a6-903e-ba32014afb15 failed: rpc error: code = FailedPrecondition desc = volume vol-ey3xpxcj currently published on a node but plugin only support OFFLINE expansion
Normal Resizing 28m (x13 over 28m) external-resizer csi-qingcloud External resizer is resizing volume pvc-e78f36e1-bb9c-40a6-903e-ba32014afb15
Normal FileSystemResizeSuccessful 26m kubelet MountVolume.NodeExpandVolume succeeded for volume "pvc-e78f36e1-bb9c-40a6-903e-ba32014afb15"
关键成功标志:
FileSystemResizeSuccessful事件spec.resources.requests.storage等于status.capacity.storage- PVC 状态为
Bound且无错误条件
四、扩容失败处理
4.1 常见错误及解决
错误1:PVC 处于挂起状态
ini
Warning VolumeResizeFailed external-resizer csi-qingcloud
resize volume failed: rpc error: code = FailedPrecondition
desc = volume currently published on a node but plugin only support OFFLINE expansion
解决方法:
- 确认所有使用该 PVC 的 Pod 已停止
- 检查是否有节点异常导致 PVC 仍被挂载
错误2:存储配额不足
ini
Warning VolumeResizeFailed external-resizer csi-qingcloud
resize volume failed: rpc error: code = ResourceExhausted
desc = quota exceeded
解决方法:
- 联系云平台管理员增加存储配额
- 或选择较小的扩容容量
4.2 恢复 PVC 到之前状态
如果扩容失败,可以尝试将 PVC 恢复到之前的状态:
perl
# 1. 回滚 PVC 配置
kubectl edit pvc <pvc-name> -n <namespace>
# 将 storage 改回原来的大小
# 2. 如果 PVC 处于异常状态,删除并重建
# 注意:确保有数据备份!
kubectl delete pvc <pvc-name> -n <namespace>
# 使用备份数据恢复
五、最佳实践与建议
5.1 事前准备
- 备份数据:在扩容前,确保有完整的数据备份
- 通知相关人员:提前通知业务方和维护窗口
- 测试环境验证:先在测试环境演练完整流程
5.2 监控与告警
yaml
# 设置 PVC 使用率监控
# PVC 使用率超过 80% 时发出告警
- alert: PVCUsageHigh
expr: (kubelet_volume_stats_used_bytes / kubelet_volume_stats_capacity_bytes) * 100 > 80
for: 5m
labels:
severity: warning
annotations:
summary: "PVC {{ $labels.persistentvolumeclaim }} usage high"
5.3 自动化扩容方案
对于需要频繁扩容的场景,可以考虑:
- 使用动态扩容工具:如 kubernetes-autoscaler
- 编写自动化脚本:将扩容流程脚本化
- 集成到 CI/CD:在发布流程中自动检查存储容量
六、不同存储方案对比
| 存储方案 | 扩容模式 | 是否需要停服 | 文件系统支持 |
|---|---|---|---|
| QingCloud CSI | Offline | 是 | ext4, xfs |
| AWS EBS CSI | Online | 否 | 大部分文件系统 |
| Azure Disk CSI | Online | 否 | 大部分文件系统 |
| Ceph RBD | Online | 否 | 大部分文件系统 |
总结
PVC 扩容是 Kubernetes 运维中的常见操作,理解其工作原理和注意事项至关重要。通过本文的步骤指南,你可以:
- 安全地完成 offline 扩容操作
- 理解扩容过程中的各个状态
- 能够诊断和解决扩容中的问题
- 建立完善的存储容量管理策略
记住,任何生产环境操作前都要先备份数据,并在非业务高峰期进行。随着 Kubernetes 和 CSI 驱动的发展,未来会有更多存储方案支持 online 扩容,进一步降低业务影响。
实战小贴士:对于关键业务,建议实现存储容量的自动化监控和预警,提前规划扩容,避免存储空间用尽导致的业务中断。