EKS 위에 올린 데이터베이스의 데이터 디렉터리가 가득 찼다. 파드는 기동에 실패하고, 볼륨을 키워야 한다. 그런데 PVC 가 쓰는 StorageClass 에 allowVolumeExpansion: false 가 걸려 있다.
용량을 늘리기 전에 무엇이 자리를 차지하는지 본다. PostgreSQL 이라면 pg_wal 이 비정상적으로 쌓여 있는 경우가 흔하고, 이때는 용량을 늘려도 다시 찬다.
kubectl exec -n <NS> <POD> -c <CONTAINER> -- df -h
kubectl exec -n <NS> <POD> -c <CONTAINER> -- du -sh /pgdata/* 2>/dev/null | sort -h | tail
pg_wal 안의 파일은 손으로 지우지 않는다. 체크포인트 이후에도 남아 있는 WAL 은 아직 소비되지 않은 복제 슬롯이나 실패하는 아카이브 명령이 붙잡고 있는 것이고, 그 상태에서 파일만 지우면 데이터베이스가 기동하지 못한다. 원인을 없애면 PostgreSQL 이 스스로 지운다.
"EFS 인 줄 알았는데 gp2 였다" 같은 착각이 자주 생긴다. 볼륨 종류에 따라 확장 방법과 가능 여부가 완전히 달라지므로 실제 값을 본다.
kubectl get pvc <PVC> -n <NS> -o jsonpath='{.spec.storageClassName}{"\n"}'
kubectl get sc <SC> -o yaml | grep -E 'provisioner|allowVolumeExpansion|type:'
kubectl get pv <PV> -o jsonpath='{.spec.csi.driver} {.spec.csi.volumeHandle}{"\n"}'
ebs.csi.aws.com 이면 EBS, efs.csi.aws.com 이면 EFS 다. EFS 는 용량 개념이 없어 PVC 의 요청 크기가 표시용일 뿐이므로 "가득 찼다" 는 증상 자체가 다른 원인이다. 사내에서 NFS 프로비저너를 EFS 위에 올린 구성이라면 provisioner 이름이 또 다르다.
allowVolumeExpansion 은 StorageClass 의 필드이고, 수정 가능한 몇 안 되는 필드 중 하나다.
kubectl patch sc <SC> -p '{"allowVolumeExpansion": true}'
kubectl patch pvc <PVC> -n <NS> --type=merge \
-p '{"spec":{"resources":{"requests":{"storage":"150Gi"}}}}'
바꾼 값은 그 StorageClass 로 만들어진 기존 PVC 에도 적용된다. 새로 만든 PVC 만 확장 가능해지는 것이 아니다. 다만 같은 StorageClass 를 다른 워크로드도 쓰고 있으므로, 이후 누구나 볼륨을 키울 수 있게 된다는 점은 인지하고 바꾼다.
진행 상황은 PVC 의 조건에서 본다.
kubectl describe pvc <PVC> -n <NS> | tail -20
kubectl get pvc <PVC> -n <NS> -o jsonpath='{.status.capacity.storage}{"\n"}'
FileSystemResizePending 이 보이면 블록 장치는 커졌고 파일 시스템 확장만 남은 것이다. 요즘 CSI 드라이버는 온라인으로 처리하지만, 드라이버 버전에 따라 파드를 한 번 재시작해야 반영되는 경우가 있다.
EBS 에는 수정 쿨다운이 있어 한 번 크기를 바꾸면 일정 시간 동안 다시 바꾸지 못한다. 한 번에 여유 있게 잡는다.
AWS 콘솔이나 CLI 로 EBS 볼륨을 직접 키우는 것은 Kubernetes 밖의 조작이다. 블록 장치는 커지지만 PVC 와 PV 의 표시 용량은 그대로이고, 파일 시스템도 자동으로 늘어나지 않는다.
aws ec2 modify-volume --volume-id <VOL_ID> --size 150
파드 안에서 파일 시스템을 직접 늘려야 한다. 파일 시스템 종류를 먼저 확인한다 — 명령이 다르다.
lsblk
df -hT /pgdata
resize2fs /dev/nvme1n1 # ext4
xfs_growfs /pgdata # xfs
resize2fs 와 xfs_growfs 는 마운트된 상태에서 확장할 수 있고, 축소가 아니라 확장이면 위험이 낮다. 위험한 것은 장치를 잘못 지정하는 것이므로 lsblk 와 df -hT 로 대상을 확정한 뒤 실행한다.
이 방법의 대가는 상태 불일치다. Kubernetes 는 여전히 옛 용량으로 알고 있으므로, 이후 정식 경로로 확장하려 할 때 이미 실제 크기가 더 큰 상태라 혼란이 생긴다. 모니터링의 용량 지표도 어긋난다. 급한 불을 끈 뒤에는 StorageClass 를 고쳐 정식 경로로 정리해 두는 편이 낫다.
StorageClass 를 고칠 권한이 없거나 프로비저너가 확장을 지원하지 않으면 새 PVC 로 옮긴다.
논리 백업으로 옮기는 방법이 가장 안전하다. 새 크기의 PVC 를 만들고, 덤프를 받아 새 인스턴스에 적재한 뒤 전환한다. 데이터베이스가 아니라면 두 PVC 를 모두 마운트한 임시 파드에서 복사한다.
spec:
containers:
- name: copy
image: busybox
command: ["sh", "-c", "cp -a /old/. /new/ && echo done && sleep 3600"]
volumeMounts:
- { name: old, mountPath: /old }
- { name: new, mountPath: /new }
원본 PVC 의 접근 모드가 ReadWriteOnce 이면 원래 파드를 먼저 내려야 같은 노드에서 마운트할 수 있다.