Kubernetes v1.37에서 오래된 유휴 PVC 찾기
PVC의 Unused 컨디션과 lastTransitionTime을 이용해 장기간 사용되지 않은 볼륨을 선별하고 정리 후보를 만드는 방법을 설명한다.
2026-09-23
PVC 정리 작업에서 먼저 바뀌는 것
파드를 삭제해도 연결됐던 PersistentVolumeClaim(PVC)은 자동으로 삭제되지 않는다. 실수로 데이터를 잃는 일을 막기 위한 동작이지만, 관리하지 않으면 더 이상 사용하지 않는 PVC가 남아 스토리지 용량과 클라우드 비용을 계속 차지할 수 있다.
이전에는 PVC의 실제 사용 여부를 알아내기 위해 파드, PersistentVolume, PVC 정보를 서로 대조해야 했다. 클러스터 규모가 커지면 별도 모니터링 파이프라인이나 스크립트가 필요해지기 쉬운 작업이었다.
Kubernetes v1.37에서는 PersistentVolumeClaimUnusedSinceTime 피처 게이트가 Beta로 승격됐으며 기본으로 활성화된다. PVC protection 컨트롤러가 각 PVC의 상태에 Unused 컨디션을 추가하므로, 관리자는 PVC 자체를 조회해 현재 참조 여부를 확인할 수 있다.
이 기능의 동작과 사용법은 Kubernetes 공식 글인 Tracking When a PersistentVolumeClaim Was Last Used에서 확인할 수 있다. 이 변경은 Kubernetes v1.37 “Garhwal” 릴리스에서 Beta로 승격된 개선 사항에 포함된다.
Unused 컨디션을 읽는 기준
PVC protection 컨트롤러는 종료되지 않은 파드가 PVC를 참조하는지에 따라 상태를 기록한다.
| 파드 참조 상태 | 컨디션 | reason |
|---|---|---|
| 종료되지 않은 파드가 참조하지 않음 | Unused=True |
NoPodsUsingPVC |
| 실행 중이거나 Pending인 파드가 참조함 | Unused=False |
PodUsingPVC |
여기서 Unused=True는 현재 종료되지 않은 파드가 해당 PVC를 참조하지 않는다는 뜻이다. 곧바로 삭제해도 된다는 보장은 아니므로, 삭제 명령을 자동화하기 전에 정리 후보를 선별하는 신호로 사용하는 편이 적절하다.
판정할 때는 파드의 상태를 함께 이해해야 한다.
Succeeded또는Failed상태로 끝난 파드는 사용 중인 것으로 계산하지 않는다.restartPolicy: Never인 배치 작업도 종료된 뒤에는 PVC가Unused=True로 전환될 수 있다.- Pending 파드는 실제로 스케줄되지 않았더라도 사용 중인 것으로 계산한다. 불가능한 노드 셀렉터 때문에 대기 중인 파드도 PVC를 참조할 의사가 있는 것으로 본다.
- 여러 파드가 같은 PVC를 참조하면 마지막으로 남은 종료 전 파드가 삭제되거나 종료된 뒤에야
Unused=True가 된다.
따라서 유휴 PVC 조회 결과를 검토할 때는 실행 중인 파드뿐 아니라 Pending 파드와 완료된 작업의 상태도 구분해야 한다.
PVC 상태에서 유휴 시점 확인하기
Unused는 Kubernetes의 표준 컨디션이므로 lastTransitionTime을 가진다. 컨디션이 False에서 True로 바뀌면 이 필드에 PVC가 유휴 상태가 된 시점이 기록된다.
특정 PVC의 전체 컨디션은 다음과 같이 확인한다.
kubectl get pvc my-data -o jsonpath='{.status.conditions[*]}' | jq .
사용하는 파드가 없다면 다음과 같은 Unused 컨디션을 볼 수 있다.
{
"lastProbeTime": null,
"lastTransitionTime": "2026-09-14T12:03:11Z",
"message": "No pods are currently referencing this PVC",
"reason": "NoPodsUsingPVC",
"status": "True",
"type": "Unused"
}
자동화에서는 전체 객체보다 필요한 필드만 조회할 수 있다.
kubectl get pvc my-data \
-o jsonpath='{.status.conditions[?(@.type=="Unused")].status}'
출력이 True라면 현재 종료되지 않은 파드가 PVC를 참조하지 않는 상태다. 유휴 기간을 판단하려면 같은 컨디션의 lastTransitionTime도 함께 사용해야 한다.
클러스터 전체에서 오래된 PVC 선별하기
모든 네임스페이스에서 유휴 상태가 30일을 넘은 PVC를 찾으려면 kubectl의 JSON 출력과 jq를 조합한다.
kubectl get pvc -A -o json | jq -r '
.items[]
| select(.status.conditions[]? | select(.type=="Unused" and .status=="True"))
| select(
(.status.conditions[] | select(.type=="Unused") | .lastTransitionTime) as $t
| (now - ($t | fromdateiso8601)) > (30 * 86400)
)
| "\(.metadata.namespace)/\(.metadata.name) unused since \(.status.conditions[] | select(.type=="Unused") | .lastTransitionTime)"
'
이 명령은 다음 조건을 모두 만족하는 PVC만 출력한다.
Unused컨디션이 존재한다.- 해당 컨디션의 상태가
True다. lastTransitionTime이후 30일보다 긴 시간이 지났다.
출력에는 네임스페이스, PVC 이름, 유휴 상태로 전환된 시각이 포함된다. 이 목록을 정기적으로 수집하면 클러스터 전체의 정리 후보를 별도 교차 조회 없이 만들 수 있다.
자동 삭제보다 후보 목록부터 운영하기
Unused=True가 의미하는 범위는 명확하다. 현재 종료되지 않은 파드가 PVC를 참조하지 않는다는 뜻이다. PVC에 남은 데이터의 필요성이나 이후 다시 연결할 계획까지 판단해 주는 상태는 아니다.
따라서 처음에는 조회 결과를 삭제 명령에 바로 연결하지 말고 검토 가능한 후보 목록으로 운영하는 편이 좋다. 후보를 만들 때는 최소한 다음 정보를 함께 남긴다.
- PVC의 네임스페이스와 이름
Unused컨디션의status- 판정 근거인
reason - 유휴 상태가 시작된
lastTransitionTime
이 방식이면 단순히 현재 비어 있는 PVC와 오랫동안 사용되지 않은 PVC를 구분할 수 있다. Pending 파드가 참조하는 PVC는 Unused=False로 유지되므로, 아직 실행되지 못한 워크로드의 볼륨을 유휴 대상으로 잘못 분류하는 일도 피할 수 있다.
상태 전환을 직접 확인하기
운영 자동화에 넣기 전에는 테스트 PVC와 파드를 이용해 상태 전환을 확인한다. 먼저 PVC를 생성한 뒤 컨디션을 조회하면 사용하는 파드가 없는 상태에서 Unused=True와 NoPodsUsingPVC를 확인할 수 있다.
이후 해당 PVC를 참조하는 파드를 만들면 다음 조회 결과가 False로 바뀐다.
kubectl get pvc my-data \
-o jsonpath='{.status.conditions[?(@.type=="Unused")].status}'
파드를 삭제한 뒤 다시 조회하면 컨디션은 Unused=True로 돌아가고 reason은 NoPodsUsingPVC가 된다.
kubectl delete pod my-app
kubectl get pvc my-data \
-o jsonpath='{.status.conditions[?(@.type=="Unused")]}'
이 전환을 확인한 다음 클러스터 전체 조회 명령을 적용하면, PVC protection 컨트롤러가 제공하는 상태와 유휴 기간을 기준으로 정리 대상을 일관되게 선별할 수 있다.