KCNA — Kubernetes and Cloud Native Associate
A Matching Disk Exists, Yet the PVC Won't Bind
한국어 원문으로 표시합니다.
목표
no-provisioner StorageClass 와 손으로 만든 PV 로, PVC 가 언제 묶이는지(WaitForFirstConsumer), 어떤 요구면 끝내 안 묶이는지(accessMode 불일치), PVC 를 지운 뒤 PV 가 어떻게 남는지(Retain → Released)를 직접 관찰합니다.
왜 중요한가
파드는 사라져도 데이터는 남아야 합니다. 쿠버네티스는 이를 위해 "디스크 그 자체(PV)" 와 "디스크를 달라는 요청(PVC)" 을
나누고, 둘을 짝지우는 일을 컨트롤러에게 맡깁니다. 그래서 PVC 가 Pending 이라는 한 가지 증상 뒤에는
"아직 쓰는 파드가 없어 일부러 기다리는 중" 과 "조건에 맞는 볼륨이 아예 없음" 이라는 전혀 다른 원인이 숨어 있습니다.
reclaim 정책도 운영에서 자주 사고가 나는 자리입니다. Delete 정책이면 PVC 하나 지운 것으로 데이터가 사라지고,
Retain 이면 데이터는 지켜지지만 PV 가 Released 로 남아 자동으로 재사용되지 않습니다. 둘의 차이를 모르고 PVC 를
지우면 복구할 수 없는 일이 생깁니다.
단계
- 네임스페이스
kcna-storage를 만듭니다. - StorageClass
local-fast(no-provisioner, WaitForFirstConsumer, Retain)를 만듭니다. - PV
pv-fast-1(1Gi, ReadWriteOnce, Retain, hostPath)을 만듭니다. - PVC
data를 만들고 소비자가 없어 Pending 에 머무는 것을 확인합니다. - 파드
writer가data를 마운트하자 PVC 가pv-fast-1에 묶이는 것을 확인합니다. - ReadWriteMany 를 요구하는 PVC
wide와 파드wider가 끝내 묶이지 못하는 것을 확인합니다. writer와data를 지우고pv-fast-1이 Released 로 남는 것을 확인합니다.- 관찰 결과를
/root/kcna-storage/report.txt에 장부로 남깁니다.
참고
kubectl describe pvc <이름> -n kcna-storage의 Events 가 "왜 아직 안 묶였는지" 를 알려 줍니다.kubectl get pv의 CLAIM 열은 Released 뒤에도 옛 PVC 이름을 기억합니다 — 그래서 다른 PVC 에 자동으로 묶이지 않습니다.- 공식 문서: 퍼시스턴트 볼륨 · 스토리지 클래스.
디스크를 나눠 줄 작업장 열기
네임스페이스 kcna-storage 를 만듭니다.
PVC 와 파드는 네임스페이스에 속하지만 PV 와 StorageClass 는 클러스터 범위입니다. 먼저 PVC 가 들어갈 네임스페이스를 준비하세요. create 를 --dry-run=client -o yaml 로 뽑아 apply 하면 반복 실행에 안전합니다.
쓰는 사람이 나타날 때까지 기다리는 저장소 등급
StorageClass local-fast 를 만듭니다. provisioner 는 kubernetes.io/no-provisioner, volumeBindingMode 는 WaitForFirstConsumer, reclaimPolicy 는 Retain 입니다.
no-provisioner 는 볼륨을 자동으로 만들지 않는다는 뜻이라, PV 는 관리자가 손으로 준비합니다. volumeBindingMode 의 기본값 Immediate 는 PVC 가 생기자마자 PV 를 짝지우고, WaitForFirstConsumer 는 그 PVC 를 쓰는 파드가 스케줄될 때까지 짝짓기를 미룹니다. StorageClass 는 kubectl create 하위 명령이 없으니 YAML(apiVersion storage.k8s.io/v1)로 적어 apply 하세요.
관리자가 손으로 깔아 둔 1Gi 디스크
PersistentVolume pv-fast-1 을 만듭니다. 용량 1Gi, accessModes [ReadWriteOnce], persistentVolumeReclaimPolicy Retain, storageClassName local-fast, hostPath 경로 /tmp/pv-fast-1.
PV 는 클러스터 범위 오브젝트라 metadata 에 namespace 가 없습니다. PVC 와 짝지어지려면 storageClassName·accessModes·용량이 요구를 만족해야 합니다. StorageClass 의 reclaimPolicy 는 동적 프로비저닝된 PV 에만 적용되므로, 손으로 만드는 PV 에는 spec 에 reclaim 정책을 직접 적어야 합니다. 만든 직후 STATUS 를 보세요.
맞는 디스크가 있는데도 PVC 가 Pending 이다
네임스페이스 kcna-storage 에 PVC data 를 만듭니다. accessModes [ReadWriteOnce], storageClassName local-fast, 요청 용량 1Gi. 아직 이 PVC 를 쓰는 파드가 없으므로 Pending 에 머뭅니다. 그 순간을 /root/kcna-storage/pending.json 에 기록하세요 — PVC 의 uid·phase·volumeName 세 키입니다. 뒤 단계에서 PVC 가 묶이고 지워져도 이 단계는 이 기록과 클러스터의 이벤트로 판정합니다.
조건이 맞는 PV 가 있어도 WaitForFirstConsumer 등급에서는 소비자(파드)가 나타나기 전까지 바인딩이 일어나지 않습니다. 이것은 고장이 아니라 설계입니다 — 파드가 어느 노드에 갈지 정해진 뒤에 그 노드에서 쓸 수 있는 볼륨을 고르기 위해서입니다. kubectl describe pvc data 의 Events 에서 이유를 읽은 뒤, kubectl get pvc data -o json 에서 필요한 세 값을 jq 로 골라 파일로 남기세요. 값을 손으로 지어내면 이벤트의 UID 와 맞지 않아 실패합니다.
파드가 나타나자 PVC 가 묶이다
네임스페이스 kcna-storage 에 파드 writer(이미지 nginx:1.27-alpine)를 만들어 PVC data 를 /data 에 마운트합니다. PVC data 가 Bound 가 되고 짝지어진 볼륨이 pv-fast-1 이면, 그 순간의 PVC uid·phase·volumeName 을 /root/kcna-storage/bound.json 에 기록합니다.
파드 spec 의 volumes 에 persistentVolumeClaim(claimName) 볼륨을 선언하고, 컨테이너의 volumeMounts 에서 그 볼륨 이름을 mountPath 에 연결합니다. 스케줄러가 파드를 노드에 놓는 순간 지연됐던 바인딩이 진행됩니다. 고정 sleep 대신 PVC 의 status.phase 를 몇 초 간격으로 다시 읽어 Bound 가 될 때까지 기다리세요.
여럿이 같이 쓰겠다는 요구는 아무도 받아 주지 않는다
네임스페이스 kcna-storage 에 PVC wide 를 만듭니다. accessModes [ReadWriteMany], storageClassName local-fast, 요청 용량 1Gi. 그리고 파드 wider(이미지 nginx:1.27-alpine)가 이 PVC 를 마운트하게 합니다. ReadWriteMany 를 제공하는 PV 가 없으므로 PVC wide 는 Bound 가 되지 않아야 합니다.
PVC 의 accessModes 는 "이 방식이 가능한 볼륨을 달라" 는 요구입니다. 클러스터에 있는 PV 는 ReadWriteOnce 하나뿐이고 그마저 이미 다른 PVC 에 묶여 있습니다. 소비자 파드가 있어도 조건을 만족하는 PV 가 없으면 PVC 는 Pending, 파드는 스케줄되지 못합니다. 05 단계와 같은 모양으로 PVC 와 파드를 만들되 accessModes 만 다르게 하세요.
PVC 를 지웠는데 디스크는 남았다
파드 writer 를 지운 다음 PVC data 를 지웁니다. reclaim 정책이 Retain 인 PV pv-fast-1 은 삭제되지 않고 Released 상태로 남아야 합니다.
사용 중인 PVC 는 보호 finalizer 때문에 파드가 사라질 때까지 지워지지 않으니 파드를 먼저 지웁니다. PVC 가 사라지면 PV 는 reclaim 정책을 따릅니다 — Delete 면 PV 도 지워지고, Retain 이면 데이터를 지키려고 Released 로 남아 다른 PVC 에 다시 묶이지 않습니다. PV 의 STATUS 가 바뀔 때까지 폴링하세요.
디스크가 어떻게 흘러갔는지 장부로 남기기
관찰한 결과를 /root/kcna-storage/report.txt 에 정확히 네 줄로 적습니다 — sc-binding-mode=WaitForFirstConsumer, pv-reclaim=Retain, pv-phase-after-release=Released, wide-pvc=Pending. 값은 실제 클러스터 상태와 일치해야 합니다.
채점기는 각 줄을 실제 StorageClass 의 volumeBindingMode, PV 의 reclaim 정책과 phase, PVC wide 의 phase 와 대조합니다. kubectl get sc,pv 와 kubectl get pvc -n kcna-storage 로 확인한 값을 그대로 옮기세요.