Kubernetes 볼륨 완벽 가이드 - 개발자 관점

📚 개요

“평범한” hostPath 실습에서 시작해서 “복잡한” PV/PVC/StorageClass까지, 쿠버네티스 스토리지의 진화 과정을 개발자 관점에서 분석합니다.


🎯 왜 볼륨이 필요한가?

컨테이너의 본질적 한계

컨테이너 = 임시적(Ephemeral)
├─ 컨테이너 재시작 → 데이터 손실 💥
├─ Pod 재스케줄링 → 데이터 손실 💥  
└─ 업데이트/롤백 → 데이터 손실 💥

애플리케이션의 데이터 지속성 요구사항

  • 데이터베이스: 데이터 영구 보존
  • 로그 파일: 분석 및 모니터링
  • 캐시: 성능 최적화
  • 설정 파일: 외부 주입

📈 스토리지 진화 단계

Level 1: hostPath (오늘의 실습 수준)

# 장점: 간단함, 직관적
# 단점: 노드 종속성, 확장성 한계
 
volumes:
- name: host-logs
  hostPath:
    path: /var/log
    type: Directory

사용 시기:

  • 개발/테스트 환경
  • 로그 수집 (DaemonSet과 조합)
  • 노드별 고유 데이터 접근

Level 2: PV/PVC (내일의 학습 목표)

# 장점: 추상화, 포터빌리티
# 단점: 수동 관리, 복잡성
 
kind: PersistentVolumeClaim
metadata:
  name: app-data
spec:
  resources:
    requests:
      storage: 10Gi

혁신점:

  • Infrastructure as Code 완성
  • 환경별 동일한 YAML 사용
  • 개발↔운영 환경 일관성

Level 3: StorageClass + Dynamic Provisioning (고급)

# 장점: 완전 자동화, 클라우드 네이티브
# 복잡성: CSI 드라이버, 클라우드 API
 
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  iopsPerGB: "50"

게임 체인저:

  • 서비스형 스토리지 (Storage as a Service)
  • 개발자는 요구사항만 명시
  • 플랫폼이 구체적 구현 처리

🔧 실무 관점: 스토리지 패턴 분석

패턴 1: 사이드카 로깅 (emptyDir)

spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - name: logs
      mountPath: /var/log/nginx
  - name: log-shipper  # 사이드카
    image: fluentd
    volumeMounts:
    - name: logs
      mountPath: /var/log/nginx
  volumes:
  - name: logs
    emptyDir: {}  # Pod 내부에서만 공유

언제 사용?

  • 동일 Pod 내 컨테이너 간 데이터 공유
  • 임시 파일, 캐시 데이터
  • 컨테이너 재시작 시 데이터 초기화 원함

패턴 2: 설정/시크릿 통합 (Projected Volume)

volumes:
- name: config-and-secrets
  projected:
    sources:
    - configMap:
        name: app-config
    - secret:
        name: db-credentials
    - serviceAccountToken:
        path: token
        expirationSeconds: 3600

혁신적인 이유:

  • 여러 소스를 하나의 디렉터리로 통합
  • 실시간 업데이트 (60초 주기)
  • 복잡한 마운트 구조 단순화

패턴 3: 데이터베이스 클러스터 (StatefulSet + volumeClaimTemplates)

spec:
  serviceName: mysql
  replicas: 3
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      storageClassName: fast-ssd
      resources:
        requests:
          storage: 10Gi

실행 결과:

mysql-0 → data-mysql-0 → 독립적인 10GB 디스크
mysql-1 → data-mysql-1 → 독립적인 10GB 디스크
mysql-2 → data-mysql-2 → 독립적인 10GB 디스크

개발자 가치:

  • 진짜 분산 데이터베이스 구현
  • 데이터 격리 자동 보장
  • 스케일링 시 데이터 일관성 유지

🚀 내일 학습할 핵심 포인트

1. PV/PVC의 진짜 의미

개발자 관점: "내가 스토리지 구현 몰라도 됨"
운영자 관점: "개발자가 인프라 몰라도 됨"
플랫폼 관점: "추상화를 통한 확장성"

2. AccessModes의 현실적 선택

Mode설명실제 사용 사례지원 스토리지
RWO한 노드만 읽기/쓰기데이터베이스, 앱 데이터거의 모든 스토리지
RWX여러 노드 읽기/쓰기공유 파일시스템, 미디어NFS, CephFS, EFS
ROX여러 노드 읽기만설정파일, 정적 자산대부분 스토리지

3. 동적 프로비저닝의 마법

# 개발자가 작성하는 것
apiVersion: v1
kind: PersistentVolumeClaim
spec:
  storageClassName: "fast-ssd"  # 요구사항만 명시
  resources:
    requests:
      storage: 10Gi
 
# 플랫폼이 자동으로 하는 일
# 1. AWS EBS gp3 10GB 볼륨 생성
# 2. PV 객체 자동 생성  
# 3. PVC-PV 자동 바인딩
# 4. Pod 스케줄링 시 볼륨 어태치

4. volumeBindingMode의 숨겨진 중요성

# WaitForFirstConsumer (AWS EBS 기본값)
volumeBindingMode: WaitForFirstConsumer
# 의미: Pod 스케줄링 후 해당 AZ에 볼륨 생성
 
# Immediate (NFS 등)  
volumeBindingMode: Immediate
# 의미: PVC 생성 즉시 PV 생성

왜 중요한가?

문제 상황 (Immediate):
PVC 생성 → us-east-1a에 EBS 생성
Pod 생성 → us-east-1b 노드에 스케줄됨
결과 → FailedAttachVolume (다른 AZ라서 어태치 불가)

해결 (WaitForFirstConsumer):
Pod 스케줄링 → us-east-1b 노드 선택됨
PV 생성 → us-east-1b에 EBS 생성
결과 → 성공적 어태치 ✅

🛠 실무 트러블슈팅 시나리오

문제 1: PVC가 Pending 상태

$ kubectl get pvc
NAME       STATUS    VOLUME   STORAGECLASS
app-data   Pending   -        fast-ssd
 
$ kubectl describe pvc app-data
Events:
  Warning  ProvisioningFailed  no volume plugin matched

해결 플로우:

1. StorageClass 존재 확인
   → kubectl get sc fast-ssd
   
2. CSI 드라이버 설치 확인  
   → kubectl get pods -n kube-system | grep csi
   
3. volumeBindingMode 확인
   → WaitForFirstConsumer라면 Pod 생성 필요

문제 2: 다중 노드에서 동시 접근 실패

# 문제가 되는 설정
spec:
  accessModes:
  - ReadWriteOnce  # 한 노드에서만 접근 가능
  
# Deployment replicas: 3 (여러 노드에 분산)
# 결과: 2개 Pod가 Pending 상태

해결책:

# Option 1: ReadWriteMany 사용 (NFS 필요)
spec:
  accessModes:
  - ReadWriteMany
  
# Option 2: StatefulSet으로 변경 (각자 PVC)
kind: StatefulSet
spec:
  volumeClaimTemplates: ...

📊 스토리지 선택 가이드

사용 사례추천 볼륨 타입이유
임시 빌드 공간Generic Ephemeral동적 생성, 자동 정리
로그 수집emptyDir + 사이드카Pod 내 공유, 단순함
설정 통합Projected Volume여러 소스 통합, 실시간 업데이트
데이터베이스PVC + StatefulSet영구 보존, 데이터 격리
공유 파일PVC (RWX) + NFS다중 접근, 일관성
정적 자산PVC (ROX)읽기 전용 공유

💡 모던 쿠버네티스 스토리지 트렌드

1. CSI 생태계 확장

  • AWS EFS CSI: 관리형 NFS 서비스
  • Secrets Store CSI: 외부 시크릿 저장소 연동
  • Local Path Provisioner: 로컬 스토리지 동적 프로비저닝

2. 스토리지 정책 자동화

# VolumeSnapshot: 백업 자동화
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: daily-backup
spec:
  source:
    persistentVolumeClaimName: app-data

3. 멀티 클러스터 스토리지

  • Rook-Ceph: 분산 스토리지 오케스트레이션
  • Portworx: 엔터프라이즈 스토리지 플랫폼

🎯 학습 로드맵

기초 → 중급

  1. emptyDir, hostPath 마스터
  2. PV/PVC 개념 이해
  3. StorageClass 동적 프로비저닝
  4. StatefulSet 패턴 활용

중급 → 고급

  1. CSI 드라이버 커스터마이징
  2. VolumeSnapshot 백업 전략
  3. 스토리지 모니터링 및 최적화
  4. 멀티 클러스터 스토리지 관리

📝 핵심 요약

개발자 관점의 가치

hostPath: "간단하지만 환경 종속적"
PV/PVC: "추상화로 환경 독립성 확보"  
StorageClass: "완전 자동화로 운영 효율성"
StatefulSet: "상태 유지 앱의 완벽한 해답"

내일 학습할 때 주목할 점

  • PV/PVC는 단순한 볼륨이 아닌 “인프라 추상화 레이어”
  • StorageClass는 **“Storage as a Service”**의 구현체
  • volumeClaimTemplates는 **“데이터 격리 자동화”**의 핵심

기억할 것: 복잡해 보이는 PV/PVC/StorageClass는 결국 개발자의 삶을 단순하게 만들기 위한 추상화입니다. 한 번 이해하면 모든 클라우드에서 동일하게 사용할 수 있는 강력한 도구가 됩니다.


작성일: 2025-11-17
실습 기반: hostPath → PV/PVC/StorageClass 진화 과정