228 lines
11 KiB
Markdown
228 lines
11 KiB
Markdown
# 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 기준도 같이 만든다
|