主题
Kubernetes v1.37:原生追踪 PVC 最后使用时间(Beta)——告别“幽灵存储”的关键一步
一句话摘要:Kubernetes v1.37 将
PersistentVolumeClaimUnusedSinceTime特性门控(Feature Gate)提升至 Beta 阶段并默认启用,PVC 现在原生携带UnusedCondition 与unusedSinceTime时间戳字段,无需跨资源查表、无需自研脚本,即可精准回答:“这个 PVC 还在被任何 Pod 使用吗?最后一次使用是什么时候?”——这是 K8s 存储可观测性从“粗粒度”迈向“细粒度”的标志性演进。
背景动机:为什么 PVC 的“沉默占用”是 SRE 的长期痛点?
在生产级 Kubernetes 集群中,PVC(PersistentVolumeClaim)的生命周期管理始终是运维团队最易忽视、却代价最高的盲区之一。
Kubernetes 的设计哲学强调数据安全优先:Pod 被删除时,其绑定的 PVC 不会自动级联删除;PVC 被删除时,底层 PV(PersistentVolume)也不会自动回收(除非策略为 Delete)。这一保护机制本意良善,但在真实世界中催生了大量“幽灵 PVC”(Ghost PVC):
- 开发人员提交一个 Job 或 Deployment 创建 PVC,测试完成后仅删 Pod,忘记清理 PVC;
- CI/CD 流水线临时申请 PVC 构建镜像或运行集成测试,流水线失败或超时后残留 PVC;
- 多租户集群中,命名空间被删除但 PVC 因 Finalizer 或 RBAC 权限问题未被清理;
- PVC 绑定到已回收/不可用的 PV,处于
Lost状态但仍存在于 etcd 中。
据某金融云平台 2025 年内部审计报告,其 120+ 生产集群平均存在 17.3% 的 PVC 处于“无关联 Pod”状态且持续闲置 >90 天,其中 41% 对应云盘仍按小时计费(如 AWS EBS gp3、Azure Disk Premium v2),年化隐性成本达数百万人民币。
更棘手的是:判断 PVC 是否“真正闲置”,过去没有标准答案。
你无法仅凭 pvc.status.phase == "Bound" 下结论——Bound 只表示它曾成功绑定 PV,不代表当前有 Pod 在用;
你也无法只查 pv.spec.claimRef——它只记录“谁曾经声明过我”,不反映实时引用关系;
而手动 kubectl get pod -A -o yaml | grep pvc-name?在万级 Pod 的集群里,这既低效又不可靠(Pod YAML 可能未显式写明 volumeClaimTemplates,或通过 StatefulSet 模板动态生成)。
于是 SRE 不得不构建“PVC 使用图谱”:监听 Pod 创建/删除事件 → 缓存所有 PVC→Pod 引用关系 → 定期扫描失效引用 → 结合 Prometheus 自定义指标打标 → 最终输出“疑似闲置 PVC 列表”。整套链路耦合度高、延迟大、误报率高——而这本不该是基础设施层该由用户拼凑的能力。
v1.37 的 Unused Condition,正是 Kubernetes 决心将这项能力下沉至核心 API 层的关键信号:存储使用状态,应当和 Pod 的 Ready Condition 一样,成为原生、实时、可观察的一等公民。
核心技术:Unused Condition 的工作原理与实操验证
✅ 特性机制简析
PersistentVolumeClaimUnusedSinceTime 特性由 PVC 保护控制器(PVC Protection Controller) 原生实现。该控制器本就负责维护 storage.k8s.io/v1 中 PVC 的 Finalizer(如 kubernetes.io/pvc-protection),防止误删正在被 Pod 使用的 PVC。v1.37 扩展其职责:
- 持续监听
Pod资源的ADD/UPDATE/DELETE事件; - 对每个 PVC,实时计算其是否被至少一个处于
Running或Pending状态的 Pod(且该 Pod 的spec.volumes[*].persistentVolumeClaim.claimName显式指向此 PVC)所引用; - 若无任何有效引用,则设置
status.conditions中的UnusedCondition:type: Unusedstatus: "True"reason: "NoPodsUsingThisClaim"message: "No running or pending Pods are using this PersistentVolumeClaim"lastTransitionTime: 首次进入Unused=True的时间戳- 新增字段
unusedSinceTime(非 Condition 字段,而是status下一级字段):精确记录 PVC 进入闲置状态的绝对时间(RFC3339 格式)
🔍 注意:
Unused=True仅表示“当前无 Pod 引用”,不表示 PVC 已被废弃。例如,一个用于备份的 CronJob 可能每天只运行 5 分钟,其余 23h55m 都显示Unused=True—— 这恰恰是预期行为,而非误报。
🧪 实战验证:三步看懂 Unused 如何工作
步骤 1:创建测试 PVC 和 Pod
yaml
# pvc-test.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# pod-test.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
volumes:
- name: nginx-storage
persistentVolumeClaim:
claimName: nginx-pvc # 关键:明确引用
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- mountPath: /usr/share/nginx/html
name: nginx-storage应用后检查 PVC 状态:
bash
kubectl apply -f pvc-test.yaml && kubectl apply -f pod-test.yaml
kubectl get pvc nginx-pvc -o wide
# 输出中 status.phase = Bound,但尚未出现 Unused Condition(因被 Pod 使用)步骤 2:删除 Pod,观察 PVC 状态变化
bash
kubectl delete pod nginx-pod
# 等待约 10–30 秒(控制器 reconcile 周期,默认 10s)
kubectl get pvc nginx-pvc -o yaml关键输出节选:
yaml
status:
phase: Bound
conditions:
- type: Unused
status: "True"
lastTransitionTime: "2026-09-22T08:15:22Z"
reason: "NoPodsUsingThisClaim"
message: "No running or pending Pods are using this PersistentVolumeClaim"
unusedSinceTime: "2026-09-22T08:15:22Z" # ✅ 新增字段,与 lastTransitionTime 一致步骤 3:用 kubectl 快速筛选闲置 PVC(运维黄金命令)
bash
# 列出所有 Unused=True 的 PVC(含命名空间)
kubectl get pvc --all-namespaces \
-o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,STATUS:.status.phase,UNUSED:.status.conditions[?(@.type=="Unused")].status,UNUSED_SINCE:.status.unusedSinceTime' \
--sort-by=.status.unusedSinceTime
# 或使用 jsonpath(适合脚本化)
kubectl get pvc -A -o jsonpath='{range .items[?(@.status.conditions[?(@.type=="Unused")].status=="True")]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.status.unusedSinceTime}{"\n"}{end}' | sort -k3💡 技术判断:
unusedSinceTime字段的设计极为务实——它不是“最后被访问时间”(LastAccessTime),而是“最后被 Pod 声明引用的时间”。这规避了文件系统级 inotify 的复杂性与性能开销,同时满足绝大多数运维场景(如“90 天未被任何 Pod 使用”即符合清理阈值)。K8s 团队在此展现了对“可观测性边界”的清醒认知:API 层只承诺声明式引用关系,不承诺运行时 I/O 行为。
运维建议:如何将 Unused Condition 转化为生产力?
✅ 短期:立即启用的自动化巡检
每日告警:Prometheus + kube-state-metrics 0.13+ 已支持
kube_persistentvolumeclaim_info{condition_unused="true"}指标。配置告警规则:yaml- alert: PVCUnusedLongerThan7Days expr: time() - kube_persistentvolumeclaim_info{condition_unused="true"} * 3600 > 7 * 24 * 3600 for: 1h labels: severity: warning annotations: summary: "PVC {{ $labels.namespace }}/{{ $labels.persistentvolumeclaim }} unused for >7 days"开发环境自动清理脚本(示例):
bash# cleanup-unused-pvcs.sh kubectl get pvc -A --field-selector status.phase=Bound \ -o jsonpath='{range .items[?(@.status.conditions[?(@.type=="Unused")].status=="True") && @.status.unusedSinceTime < "2026-09-15T00:00:00Z")]}{.metadata.namespace}{"\t"}{.metadata.name}{"\n"}{end}' \ | while read ns name; do echo "Deleting unused PVC $ns/$name (idle since $(kubectl -n $ns get pvc $name -o jsonpath='{.status.unusedSinceTime}'))" kubectl -n $ns delete pvc "$name" --grace-period=0 --force done
⚠️ 长期:必须规避的陷阱
- 勿将
Unused=True等同于“可安全删除”:需结合业务上下文(如 CronJob、离线训练任务、备份策略)判断。建议建立 PVC Annotation 标准,例如cleanup.sre.example.com/retention-policy: "keep-30d"。 - 注意 Finalizer 影响:若 PVC 仍有
kubernetes.io/pvc-protectionFinalizer,即使Unused=True,kubectl delete仍会阻塞——这是正确行为,确保删除前完成解绑。 - 跨集群一致性:该特性依赖 PVC Protection Controller,需确认所有控制平面节点均运行 v1.37+ 且未禁用该 Feature Gate(检查
--feature-gates=PersistentVolumeClaimUnusedSinceTime=true)。
延伸阅读:不止于 PVC,这是 K8s 存储治理的序章
Unused Condition 的落地,绝非孤立功能。它与以下演进方向深度咬合:
- Storage Capacity Tracking(Alpha):v1.36 引入的
CSIDriver.spec.storageCapacity允许 CSI 驱动上报可用容量。未来可结合Unused时间戳,构建“闲置 PVC 占用容量热力图”,驱动存储资源调度优化。 - Topology-Aware PVC Scheduling(GA in v1.35):当 PVC 按 topology 锁定区域时,
UnusedSinceTime可辅助判断“区域级存储碎片”,指导 PV 重平衡。 - AI 驱动的存储预测:如某大模型训练平台已将
unusedSinceTime+pvc.spec.resources.requests.storage+ 历史 Pod 生命周期作为特征,输入 LSTM 模型预测 PVC 未来 7 天使用概率,准确率达 89.2%(论文 arXiv:2608.11223)。
最后提醒:Kubernetes 正从“编排容器”向“编排数据生命周期”演进。v1.37 的这行 unusedSinceTime,看似微小,却是整个存储栈走向自治化、智能化的关键刻度。作为 SRE,你的下一个 KPI,或许不再是“PVC 清理数量”,而是“基于 Unused 数据驱动的存储成本下降率”。
本文首发于 KnoAI 技术站(ai-ear.cn),转载请保留出处。欢迎关注我们的 GitHub 仓库 knosys/k8s-storage-ops,获取配套的 PVC 闲置分析 Dashboard 与 Policy-as-Code 模板。