11 KiB
storage / PVC 기준
목적
PVC는 단순히 "데이터를 남기기 위한 옵션"이 아니라,
- 어떤 워크로드가 상태를 가지는지
- 그 상태의 수명과 복구 단위가 무엇인지
- 어떤 storage class / access mode / reclaim policy / binding mode가 필요한지
- snapshot / expansion 지원이 필요한지 를 먼저 고정한 뒤에 사용한다.
이 문서의 목표는 다음과 같다.
- 상태 저장 워크로드와 무상태 워크로드를 저장소 기준으로 명확히 구분한다
- separate PVC 남발을 막는다
- K3s 기본 local-path provisioner의 운영 사용 범위를 통제한다
- PVC lifecycle과 backup/restore 단위를 먼저 고정한다
- StorageClass / VolumeSnapshotClass / reclaim policy / binding mode를 선언적으로 명시한다
공식 의미 (Kubernetes 기준)
- PV는 클러스터의 저장소 리소스이며 Pod lifecycle과 독립적이다.
- PVC는 저장소에 대한 요청(size, access mode, StorageClass, volumeMode 등)이다.
- StorageClass는 동적 프로비저닝 파라미터,
reclaimPolicy,allowVolumeExpansion,volumeBindingMode,mountOptions를 정의한다. reclaimPolicy는 PV 해제 시 동작을 결정한다. 동적 프로비저닝 PV의 기본값은Delete다. 운영 데이터가 있으면 StorageClass에서Retain을 명시한다.volumeBindingMode의 기본값은Immediate이며, topology-aware / late-binding이 필요하면WaitForFirstConsumer를 사용한다.hostPath는 single-node testing 전용이다. 운영 클러스터에서 사용하지 않는다.- K3s는 Rancher Local Path Provisioner를 기본 제공해 노드 로컬 저장소를 사용할 수 있지만, RWO만 지원하고 snapshot/expansion은 지원하지 않는다.
- VolumeSnapshot / VolumeSnapshotContent / VolumeSnapshotClass는 CSI snapshot을 위한 K8s API다.
deletionPolicy: Retain/Delete를 정책에 맞게 선택한다. - StatefulSet은
persistentVolumeClaimRetentionPolicy로 삭제/스케일다운 시 PVC 보존 여부를 제어할 수 있다.
기본 규칙
1. PVC는 상태가 있을 때만 사용
다음 중 하나가 아니면 PVC를 붙이지 않는다.
- 재시작 후에도 유지되어야 하는 데이터가 있음
- Pod 교체와 무관하게 보존되어야 하는 파일/데이터가 있음
- 복구 대상이 되는 저장 상태가 있음
- 애플리케이션이 명시적으로 영속 저장소를 요구함
금지:
- "혹시 몰라서" PVC 추가
- 로그/캐시/임시 파일을 습관적으로 PVC에 저장
- stateless 앱에 관성적으로 PVC 부착
2. PVC 존재만으로 StatefulSet을 결정하지 않는다
PVC가 있다고 무조건 StatefulSet은 아니다.
먼저 묻는다.
- Pod마다 고유한 저장소가 필요한가?
- stable network identity가 필요한가?
- 순서 있는 확장/축소가 필요한가?
아니면:
- Deployment + 단일 PVC(RWO, replicas 1) 또는 Deployment + RWX PVC 도 가능하다.
3. separate PVC는 "데이터 수명과 복구 단위가 다를 때만"
하나의 워크로드가 여러 PVC를 가져도 되는 경우는 아래와 같다.
- 데이터 종류별 수명주기가 다름
- backup/restore 단위가 다름
- 성능 요구(StorageClass) 또는 IOPS 특성이 다름
- 보안/접근 제어 단위가 다름
- 장애 시 독립적으로 보존/삭제되어야 함
금지:
- 디렉터리 몇 개를 기계적으로 PVC로 분리
- mount path별로 습관적으로 PVC 추가
- 이유 없이 "앱 데이터/설정/로그"를 모두 개별 PVC로 분리
4. 기본 원칙은 "적게, 명확하게"
기본적으로는 하나의 워크로드 / 하나의 상태 저장 목적 / 하나의 PVC를 먼저 검토한다. 분리는 정당한 이유(#3)가 있을 때만 한다.
5. StorageClass는 항상 명시적으로 지정
PVC는 storageClassName을 항상 명시한다. 클러스터 default annotation에 의존하지 않는다.
기본:
- 운영 표준 StorageClass 3~5개를 미리 정의 (예:
fast-ssd-retain,standard-delete,archive-retain,rwx-shared) - 성능/복제/노드 종속성 차이가 있으면 workload별로 구분
- 각 StorageClass는
provisioner,reclaimPolicy,volumeBindingMode,allowVolumeExpansion을 모두 선언
6. StorageClass volumeBindingMode 기본값은 WaitForFirstConsumer
운영 표준은 WaitForFirstConsumer다.
이유:
- Pod가 스케줄되는 노드의 topology(zone, node-local disk, GPU affinity 등)에 맞춰 PV를 바인딩한다
Immediate는 PVC 생성 즉시 PV를 바인딩하므로, 이후 Pod가 해당 노드/zone에 스케줄되지 못하는 상황이 생긴다- K3s local-path provisioner는 노드 로컬이므로 반드시
WaitForFirstConsumer여야 한다
Immediate 허용 예외:
- 네트워크 스토리지(Ceph, NFS, S3 CSI 등)이고 topology 제약이 없는 경우
- 사전에 PV를 warm-up 해야 하는 특수 케이스
7. StorageClass reclaimPolicy는 데이터 등급에 맞춘다
동적 프로비저닝의 기본 reclaimPolicy는 Delete다. 이는 PVC 삭제 시 PV와 데이터가 사라진다는 뜻이다.
기본:
- production stateful data (DB, object store backend, identity store 등) →
Retain - dev/test, ephemeral cache, rebuild-safe data →
Delete Retain을 쓰면 PVC 삭제 후 남은 PV를 정리하는 책임이 운영자에게 생긴다. runbook에 정리 절차를 명시한다.
8. allowVolumeExpansion은 기본 true로 두되 축소는 불가
PVC 확장 요구는 자주 생긴다. StorageClass에서 allowVolumeExpansion: true를 기본으로 둔다.
주의:
- PVC 용량 축소는 K8s가 지원하지 않는다
- 파일시스템 online expansion 지원 여부는 CSI 드라이버마다 다르다
- 확장 후 Pod 재시작이 필요한 드라이버가 있다
9. AccessMode는 실제 요구에 맞게 고른다
기본:
- 단일 writer면
ReadWriteOnce(RWO) - 동일 노드의 여러 Pod가 공유 필요시
ReadWriteOncePod(K8s 1.27+) 또는 RWO - 여러 Pod/노드 동시 read/write가 진짜 필요할 때만
ReadWriteMany(RWX) - 읽기 전용 공유는
ReadOnlyMany(ROX)
편의상 RWX를 기본값으로 두지 않는다. RWX는 NFS/CephFS 같은 별도 스토리지 백엔드를 요구한다.
10. K3s local-path provisioner는 운영에서 기본값 아님
K3s 기본 local-path provisioner의 하드 제약:
- RWO 전용 (RWX 불가)
- VolumeSnapshot 미지원
- VolumeExpansion 미지원
- 노드 로컬이므로 Pod가 특정 노드에 pin 됨 → 노드 장애 시 데이터 접근 불가
- backup은 노드 파일시스템에 직접 접근해야 함
기본:
- dev/test: 허용
- production: Longhorn, OpenEBS, Rook-Ceph, 또는 클라우드 CSI driver(EBS, PD, Azure Disk 등)로 교체
- 불가피하게 prod에서 local-path를 쓸 경우
backup-restore.md와 반드시 연동하고 노드 affinity/zone 분리를 명시
11. hostPath 직접 사용 금지
운영 PV/PVC에 hostPath를 사용하지 않는다.
예외:
- 학습/단일 노드 로컬 테스트
- 매우 제한된 디버깅 용도 (CSI driver 진단 등)
운영 표준으로 채택하지 않는다.
12. VolumeSnapshotClass를 StorageClass와 1:1로 매칭
snapshot 대상 PVC가 있는 StorageClass는 대응되는 VolumeSnapshotClass를 반드시 정의한다.
기본:
driver는 StorageClass의 provisioner와 맞춤deletionPolicy는 운영 데이터면Retain, ephemeral이면Delete- snapshot class는
labels로 RPO/retention 정책과 연결
13. PVC lifecycle은 workload 생성 전에 문서화
PVC를 만들기 전에 아래를 정한다.
- 누가 생성하는가 (Helm, Kustomize, Operator, manual)
- 누가 삭제하는가 (GitOps sync, 운영자 수동)
- scale down 시 어떻게 되는가
- workload 삭제 시 어떻게 되는가
- backup 대상인가 (어떤 RPO/RTO)
- restore 단위인가 (PVC / VolumeSnapshot / backup tool 별)
"삭제하면 같이 정리되겠지"를 금지한다.
14. StatefulSet의 PVC retention policy를 명시적으로 검토
StatefulSet을 쓰는 경우 persistentVolumeClaimRetentionPolicy.whenDeleted / whenScaled를 기본값에 두지 않는다.
기본:
- 운영 데이터: 둘 다
Retain - ephemeral 데이터: 둘 다
Delete - 혼용시 명시적 이유를 주석에 남김
15. Pod와 PVC는 같은 namespace 소유권
PVC는 Pod와 같은 namespace에서 사용된다. 스토리지도 workload의 namespace 소유권을 따라간다.
금지:
- "공용 저장소 namespace"에 무분별하게 PVC 몰아넣기
- 여러 서비스가 의미 없이 같은 PVC를 기대하는 구조
16. 워크로드별 기본 선택
| Workload | 기본 PVC | StorageClass | AccessMode | Snapshot |
|---|---|---|---|---|
| auth-server | 없음 | - | - | - |
| test-server | 없음 | - | - | - |
| ingress-controller | 없음 | - | - | - |
| migration-flyway (Job) | 없음 | - | - | - |
| Keycloak (external DB) | 없음 | - | - | - |
| PostgreSQL / CNPG | 필수 | fast-ssd-retain | RWO | 필수 |
| Vault (raft) | 필수 | fast-ssd-retain | RWO | 필수 |
| MinIO | 필수 | standard-retain | RWO | 보조 (replication 우선) |
17. 로그와 임시 파일은 PVC 기본 금지
다음은 기본적으로 PVC에 저장하지 않는다.
- application log (→ stdout + 로그 수집기)
- temp file (→
emptyDir) - cache (→
emptyDir또는 memory-backed) - rendered config copy
- transient upload staging
정말 영속화가 필요하면 이유를 주석에 명시한다.
18. backup/restore와 반드시 연결
PVC를 허용한 워크로드는 반드시 아래와 연결한다.
backup-restore.md(Velero schedule, snapshot class, RPO/RTO)operations-runbook-upgrade-rollback.md(복구 절차)
PVC가 생기면 복구 전략도 같이 생겨야 한다. 백업 없는 PVC는 merge 금지.
19. 파일시스템 / 블록 모드 명시
volumeMode는 기본 Filesystem이지만, DB raw block 같은 경우 Block을 쓸 수 있다. DB 운영이 요구하지 않으면 Filesystem 고정.
20. securityContext와 fsGroup
PVC를 쓰는 Pod는 securityContext.fsGroup 또는 fsGroupChangePolicy: OnRootMismatch를 명시해서 permission 문제를 예방한다. restricted PSA 하에서는 runAsNonRoot: true, runAsUser, fsGroup을 모두 설정한다.
프로젝트 기준 요약
- PVC는 상태가 있을 때만, separate PVC는 수명/복구 단위가 다를 때만
- StorageClass는 항상 명시,
volumeBindingMode: WaitForFirstConsumer기본,reclaimPolicy는 데이터 등급에 맞춤 - 동적 프로비저닝 기본
reclaimPolicy=Delete를 인지하고 운영 데이터는Retain명시 - K3s local-path는 RWO / no snapshot / no expansion — prod 기본값 아님
- VolumeSnapshotClass를 StorageClass와 매칭해서 정의
- StatefulSet PVC retention policy 명시
- 로그/임시 파일은 PVC 기본 금지
- PVC가 생기면 backup/restore 기준도 같이 만든다