Kubernetes Storage 이해하기: File, Block, Object Storage부터 PV, PVC, StorageClass까지

mizu·2026년 8월 27일

K8S

목록 보기
5/10

Kubernetes에서 애플리케이션을 실행하다 보면 데이터 저장 문제가 생긴다.

Pod와 컨테이너는 영구적인 존재가 아니다. 장애나 배포로 인해 기존 Pod가 삭제되고 새로운 Pod로 교체될 수 있으며, 새 Pod가 반드시 이전 Pod와 같은 Node에서 실행된다는 보장도 없다.

컨테이너 내부 파일시스템에만 데이터를 저장한다면 컨테이너가 교체될 때 데이터가 함께 사라질 수 있다. 따라서 데이터베이스와 같이 데이터를 지속해서 보관해야 하는 애플리케이션에는 Pod의 생명주기와 분리된 스토리지가 필요하다.

Kubernetes는 이를 위해 Volume, PersistentVolume, PersistentVolumeClaim, StorageClass 등의 스토리지 추상화를 제공한다. Kubernetes Volumes 공식 문서

이번 글에서는 먼저 스토리지의 기본 유형을 살펴보고, Kubernetes에서 영구 스토리지가 제공되는 과정을 정리한다.

1. File, Block, Object Storage

스토리지는 데이터를 저장하고 접근하는 방식에 따라 크게 File Storage, Block Storage, Object Storage로 나눌 수 있다.

구분데이터 관리 단위접근 방식대표적인 용도
File Storage파일과 디렉터리파일 경로공유 디렉터리, 문서, 정적 파일
Block Storage일정 크기의 블록디스크 장치데이터베이스, VM 디스크
Object Storage객체HTTP API와 객체 키이미지, 동영상, 백업, 로그

File Storage

File Storage는 데이터를 파일과 디렉터리 구조로 관리한다.

/shared
├── documents
│   └── report.pdf
└── images
    └── profile.png

사용자는 /shared/images/profile.png와 같은 경로를 이용해 데이터에 접근한다. 여러 서버가 하나의 파일시스템을 공유해야 하는 환경에서 많이 사용된다.

대표적인 예시는 다음과 같다.

  • NFS
  • Amazon EFS
  • Azure Files
  • Google Filestore

장점:

  • 디렉터리 구조가 직관적이다.
  • 여러 클라이언트가 파일을 공유하기 쉽다.
  • 기존 애플리케이션과 연결하기 쉽다.

단점:

  • 파일 잠금과 권한 관리가 필요하다.
  • 대규모 트랜잭션이나 높은 디스크 성능이 필요한 워크로드에는 한계가 있을 수 있다.

Block Storage

Block Storage는 데이터를 일정한 크기의 블록으로 나누어 저장한다.

운영체제에서는 일반적으로 하나의 디스크 장치처럼 인식한다.

/dev/sdb

애플리케이션에서 사용하려면 해당 장치에 파일시스템을 생성하고 특정 디렉터리에 마운트해야 한다.

Block Device
    ↓
Filesystem 생성
    ↓
/data에 Mount
    ↓
Application에서 사용

대표적인 예시는 다음과 같다.

  • Amazon EBS
  • Azure Managed Disk
  • Google Persistent Disk
  • SAN

장점:

  • 비교적 낮은 지연 시간과 높은 성능을 제공한다.
  • 데이터베이스와 같이 빈번한 읽기·쓰기가 발생하는 워크로드에 적합하다.
  • 애플리케이션에서 일반 디스크처럼 사용할 수 있다.

단점:

  • 하나의 볼륨을 여러 Node에서 동시에 사용하는 데 제한이 있을 수 있다.
  • 파일 공유 기능은 별도로 구성해야 한다.

Object Storage

Object Storage는 데이터를 객체 단위로 저장한다. 각 객체는 일반적으로 다음 요소로 구성된다.

  • 실제 데이터
  • 메타데이터
  • 객체를 식별하는 고유한 Key

파일시스템 경로 대신 HTTP API와 객체 Key를 이용해 데이터에 접근한다.

Bucket: application-data
Key: images/profile.png

대표적인 예시는 다음과 같다.

  • Amazon S3
  • Azure Blob Storage
  • Google Cloud Storage
  • MinIO

장점:

  • 대규모 데이터를 저장하기 쉽다.
  • 높은 확장성과 내구성을 제공한다.
  • 이미지, 동영상, 로그, 백업 파일 저장에 적합하다.

단점:

  • 일반적인 로컬 파일시스템처럼 직접 사용할 수 없다.
  • 파일 일부를 임의로 수정하는 작업에는 적합하지 않다.
  • 애플리케이션이 API 또는 전용 클라이언트를 이용해야 한다.

Kubernetes에서의 차이

Kubernetes의 일반적인 Volume과 PV/PVC는 주로 File Storage 또는 Block Storage를 Pod에 연결할 때 사용한다.

Object Storage는 일반적으로 다음처럼 애플리케이션이 API를 통해 직접 접근한다.

Pod → Object Storage API → Bucket

일부 CSI 드라이버나 FUSE 기반 솔루션을 사용하면 Object Storage를 파일시스템처럼 마운트할 수도 있다. 하지만 Object Storage가 본래 Block Storage나 File Storage와 동일한 의미의 파일시스템인 것은 아니다.


2. Kubernetes에 Volume이 필요한 이유

컨테이너 내부에 생성된 파일은 기본적으로 컨테이너의 생명주기에 영향을 받는다.

컨테이너가 재시작되는 경우 Kubernetes Volume에 저장된 데이터는 유지될 수 있지만, 컨테이너의 쓰기 가능한 레이어에만 저장된 데이터는 보존되지 않을 수 있다. 또한 Pod 자체가 삭제되면 Pod의 생명주기에 종속된 임시 Volume도 함께 제거될 수 있다.

Kubernetes Volume은 다음 문제를 해결한다.

  • 컨테이너 재시작 후에도 데이터 유지
  • 하나의 Pod 안에 있는 여러 컨테이너 간 데이터 공유
  • Pod와 독립적으로 유지되는 영구 데이터 사용
  • ConfigMap과 Secret 등의 데이터를 파일로 제공

Pod에서는 .spec.volumes에 사용할 Volume을 선언하고, 컨테이너의 .volumeMounts에서 해당 Volume을 마운트할 경로를 지정한다. Kubernetes Volumes 공식 문서

apiVersion: v1
kind: Pod
metadata:
  name: volume-example
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: cache-volume
          mountPath: /cache
  volumes:
    - name: cache-volume
      emptyDir: {}

이 예제에서 /cache에 저장된 데이터는 컨테이너가 재시작되어도 같은 Pod가 유지되는 동안에는 남아 있다.

하지만 emptyDir은 Pod의 생명주기에 종속된다. Pod가 삭제되면 해당 데이터도 삭제된다. 따라서 데이터베이스와 같이 Pod가 교체된 후에도 데이터를 유지해야 한다면 PersistentVolume이 필요하다.


3. PersistentVolume과 PersistentVolumeClaim

Kubernetes는 스토리지를 제공하는 부분과 사용하는 부분을 분리하기 위해 다음 두 리소스를 사용한다.

  • PersistentVolume, 줄여서 PV
  • PersistentVolumeClaim, 줄여서 PVC

PersistentVolume

PV는 Kubernetes 클러스터에서 사용할 수 있도록 준비된 스토리지 리소스다.

Node가 클러스터의 컴퓨팅 리소스를 나타낸다면, PV는 클러스터의 스토리지 리소스를 나타낸다고 이해할 수 있다.

PV는 다음과 같은 정보를 포함한다.

  • 스토리지 용량
  • 접근 모드
  • 볼륨 모드
  • StorageClass
  • Reclaim Policy
  • 실제 스토리지와 연결하는 정보

PV는 특정 Namespace에 속하지 않는 클러스터 범위 리소스다.

PersistentVolumeClaim

PVC는 사용자가 필요한 스토리지를 요청하는 리소스다.

사용자는 실제 스토리지가 Amazon EBS인지 NFS인지 알 필요 없이 다음 조건을 선언한다.

  • 필요한 용량
  • 접근 모드
  • StorageClass
  • 파일시스템 또는 Raw Block 사용 여부

PVC는 특정 Namespace에 속하는 Namespace 범위 리소스다.

Kubernetes API 문서에서도 PVC를 사용자의 영구 볼륨 요청이자 해당 볼륨에 대한 Claim으로 정의한다. PersistentVolumeClaim API

PV와 PVC의 관계

PV와 PVC의 관계는 Node와 Pod의 관계에 비유할 수 있다.

컴퓨팅 리소스스토리지 리소스
Node가 CPU와 메모리를 제공PV가 스토리지 용량을 제공
Pod가 필요한 자원을 요청PVC가 필요한 스토리지를 요청
Scheduler가 Pod와 Node를 연결Control Plane이 PVC와 PV를 연결

전체 흐름은 다음과 같다.

Storage
   ↓
PersistentVolume
   ↑
PersistentVolumeClaim
   ↑
Pod

조금 더 자연스럽게 표현하면 다음과 같다.

Pod → PVC 요청 → PV와 Binding → 실제 Storage 사용

Pod는 PV를 직접 선택하는 대신 PVC를 참조한다. Kubernetes Control Plane은 PVC의 조건을 만족하는 PV를 찾아 둘을 연결한다.


4. 정적 프로비저닝

정적 프로비저닝에서는 관리자가 실제 스토리지와 PV를 미리 생성한다.

관리자
  ↓
실제 Storage 생성
  ↓
PV 생성
  ↓
사용자가 PVC 생성
  ↓
조건에 맞는 PV와 Binding

예를 들어 다음과 같은 PV를 생성할 수 있다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 10Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: /mnt/data

hostPath는 특정 Node의 로컬 경로를 사용하므로 다중 Node 운영 환경의 일반적인 영구 스토리지로는 적합하지 않다. 위 예제는 구조를 이해하기 위한 학습용이다.

사용자는 다음 PVC를 생성한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: example-pvc
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

Control Plane은 다음 조건 등을 확인해 적절한 PV를 찾는다.

  • StorageClass
  • Access Mode
  • Volume Mode
  • 요청한 용량을 충족하는지
  • Selector 조건

조건에 맞는 PV를 찾으면 PV와 PVC의 상태가 Bound로 변경된다.

kubectl get pv
kubectl get pvc
NAME         CAPACITY   ACCESS MODES   STATUS   CLAIM
example-pv   10Gi       RWO            Bound    default/example-pvc

PVC가 5Gi를 요청하고 10Gi PV에 연결됐더라도, 남은 5Gi를 다른 PVC에 나누어 할당하는 것은 아니다. 일반적으로 하나의 PV는 하나의 PVC에 바인딩된다.


5. Pod에서 PVC 사용하기

Pod에서는 persistentVolumeClaim을 이용해 PVC를 참조한다.

apiVersion: v1
kind: Pod
metadata:
  name: storage-pod
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - name: application-data
          mountPath: /usr/share/nginx/html
  volumes:
    - name: application-data
      persistentVolumeClaim:
        claimName: example-pvc

리소스 간 관계는 다음과 같다.

Pod
 └─ volumeMounts: 컨테이너 내부 경로
      ↑
    Volume
      ↑
    PVC
      ↕ Binding
     PV
      ↓
 실제 Storage

여기서 각 리소스의 역할을 구분하는 것이 중요하다.

  • volumeMounts: 컨테이너 내부에서 Volume이 보이는 경로
  • volumes: Pod가 사용할 Volume 정의
  • PVC: 필요한 스토리지의 조건
  • PV: 실제 스토리지를 나타내는 Kubernetes 리소스
  • 실제 Storage: NFS, EBS, Azure Disk 등의 저장 장치

6. Access Mode

PV와 PVC에는 스토리지를 어떤 방식으로 마운트할지 나타내는 Access Mode가 있다.

Access Mode약어의미
ReadWriteOnceRWO하나의 Node에서 읽기·쓰기로 마운트
ReadOnlyManyROX여러 Node에서 읽기 전용으로 마운트
ReadWriteManyRWX여러 Node에서 읽기·쓰기로 마운트
ReadWriteOncePodRWOP클러스터 전체에서 하나의 Pod만 읽기·쓰기로 마운트

여기서 ReadWriteOnce는 “하나의 Pod만 사용 가능”이라는 뜻이 아니다.

정확히는 하나의 Node에서 읽기·쓰기로 마운트할 수 있다는 의미다. 따라서 같은 Node에서 실행되는 여러 Pod가 해당 볼륨을 사용할 가능성이 있다. 하나의 Pod만 사용하도록 제한하려면 지원되는 CSI 환경에서 ReadWriteOncePod를 사용해야 한다.

또한 모든 스토리지 유형이 모든 Access Mode를 지원하는 것은 아니다. 예를 들어 일반적인 Block Storage는 주로 RWO로 사용하고, NFS 계열의 File Storage는 RWX를 지원하는 경우가 많다.


7. Volume Mode

volumeMode는 Volume을 Pod에 어떤 형태로 제공할지 지정한다.

Filesystem

기본값은 Filesystem이다.

Block Device에 파일시스템을 생성한 뒤 디렉터리 형태로 컨테이너에 마운트한다.

volumeMode: Filesystem
Block Device
    ↓
Filesystem
    ↓
Container의 /data에 Mount

Block

Block을 지정하면 파일시스템을 생성하지 않고 Raw Block Device 형태로 컨테이너에 제공한다.

volumeMode: Block

Raw Block Device를 직접 다루는 애플리케이션에서 사용할 수 있지만, 일반적인 애플리케이션에서는 Filesystem 방식이 더 많이 사용된다.


8. StorageClass란?

정적 프로비저닝에서는 관리자가 사용자 요청을 예상하고 PV를 미리 만들어야 한다.

사용자가 10Gi 스토리지를 요청했는데 적절한 PV가 없다면 PVC는 Pending 상태로 남는다.

StorageClass는 이런 문제를 해결하기 위해 스토리지의 종류와 생성 방법을 정의한다.

공식 문서에서는 StorageClass를 관리자가 제공하는 스토리지의 클래스를 설명하는 방법으로 정의한다. 클래스는 성능 등급, 백업 정책 또는 관리자가 정한 다른 정책을 나타낼 수 있다. Kubernetes StorageClass 공식 문서

예를 들면 다음과 같이 구분할 수 있다.

StorageClass의미
fast-ssd고성능 SSD
standard일반적인 범용 스토리지
archive저렴한 장기 보관용 스토리지

StorageClass는 PV와 마찬가지로 특정 Namespace에 속하지 않는 클러스터 범위 리소스다.

StorageClass에는 주로 다음 정보가 포함된다.

  • provisioner: 스토리지를 생성할 주체
  • parameters: 스토리지 생성 옵션
  • reclaimPolicy: PVC 삭제 후 스토리지 처리 방법
  • volumeBindingMode: 볼륨 생성 및 바인딩 시점
  • allowVolumeExpansion: 볼륨 확장 허용 여부
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-storage
provisioner: example.com/csi-driver
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

provisionerparameters는 사용하는 클라우드 환경과 CSI 드라이버에 따라 달라진다.


9. 동적 프로비저닝

동적 프로비저닝은 PVC가 생성됐을 때 필요한 스토리지와 PV를 자동으로 생성하는 방식이다.

Kubernetes 공식 문서에서는 동적 프로비저닝을 스토리지 볼륨을 요청 시점에 생성하는 기능으로 설명한다.

사용자가 PVC 생성
        ↓
StorageClass 확인
        ↓
Provisioner가 실제 Storage 생성
        ↓
PV 자동 생성
        ↓
PVC와 PV Binding
        ↓
Pod에서 사용

사용자는 PV를 직접 만들지 않고 필요한 StorageClass와 용량만 요청한다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: application-pvc
spec:
  storageClassName: fast-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 20Gi

이 PVC가 생성되면 fast-storage에 설정된 Provisioner가 실제 볼륨과 PV를 자동으로 생성한다.

정적 프로비저닝과 동적 프로비저닝 비교

구분정적 프로비저닝동적 프로비저닝
PV 생성관리자가 미리 생성PVC 요청에 따라 자동 생성
실제 Storage 생성관리자가 직접 생성Provisioner가 자동 생성
StorageClass선택 사항동적 생성 정책으로 사용
운영 부담비교적 큼비교적 작음
확장성요청 증가에 수동 대응요청에 따라 자동 대응

10. volumeBindingMode

StorageClass의 volumeBindingMode는 PV를 언제 생성하고 PVC에 연결할지를 결정한다.

Immediate

PVC가 생성되면 즉시 볼륨을 생성하고 바인딩한다.

volumeBindingMode: Immediate

문제는 Pod가 어느 Node에 배치될지 결정되기 전에 스토리지가 먼저 생성될 수 있다는 것이다.

가용 영역에 종속된 Block Storage라면 다음 문제가 발생할 수 있다.

Volume: Zone A에 생성
Pod: Zone B에 스케줄링 시도
→ Volume 연결 불가

WaitForFirstConsumer

PVC를 사용하는 Pod가 생성되고 스케줄링될 때까지 볼륨 생성을 기다린다.

volumeBindingMode: WaitForFirstConsumer

Scheduler가 Pod의 Node Affinity, 리소스 요청, 가용 영역 등을 고려한 후 적절한 위치에 볼륨을 생성할 수 있다.

Topology 제약이 있는 스토리지에서는 WaitForFirstConsumer가 특히 중요하다.


11. Reclaim Policy

Reclaim Policy는 PVC가 삭제된 후 PV와 실제 스토리지를 어떻게 처리할지 결정한다.

Retain

persistentVolumeReclaimPolicy: Retain

PVC가 삭제돼도 PV와 실제 데이터는 자동으로 삭제되지 않는다.

중요한 데이터를 보호할 수 있지만, 관리자가 직접 정리하고 재사용 절차를 수행해야 한다.

Delete

persistentVolumeReclaimPolicy: Delete

PVC가 삭제되면 동적으로 생성된 PV와 외부 스토리지도 함께 삭제될 수 있다.

동적 프로비저닝으로 생성된 PV는 일반적으로 StorageClass의 Reclaim Policy를 상속한다. 공식 문서에 따르면 동적 프로비저닝된 PV의 기본 Reclaim Policy는 Delete다. 중요한 데이터를 다룬다면 StorageClass 설정을 반드시 확인해야 한다. PV Reclaim Policy 공식 문서

PVC를 삭제하기 전에 “Kubernetes 리소스만 삭제되는지, 실제 클라우드 디스크까지 삭제되는지”를 반드시 확인해야 한다.


12. PV와 PVC의 상태 확인

PV 조회

kubectl get pv

PV는 클러스터 범위 리소스이므로 Namespace를 지정하지 않는다.

PVC 조회

kubectl get pvc
kubectl get pvc -n <namespace>

상세 정보 확인

kubectl describe pv <pv-name>
kubectl describe pvc <pvc-name>

PVC가 Pending이라면 다음 항목을 확인한다.

  • 요청한 StorageClass가 존재하는가
  • Provisioner가 정상적으로 실행 중인가
  • PVC의 Access Mode를 스토리지가 지원하는가
  • 요청 용량을 만족하는 PV가 존재하는가
  • PV와 PVC의 storageClassName이 일치하는가
  • CSI Controller 또는 Node Plugin에 오류가 있는가
  • Pod 스케줄링과 가용 영역에 문제가 있는가
  • PVC 또는 Pod의 Event에 오류가 기록됐는가
kubectl get storageclass
kubectl describe storageclass <storageclass-name>
kubectl get events --sort-by=.metadata.creationTimestamp

스토리지 문제를 진단할 때는 리소스의 현재 상태뿐 아니라 Events를 함께 확인하는 것이 중요하다.


13. 전체 흐름 정리

정적 프로비저닝

관리자가 실제 Storage 생성
          ↓
        PV 생성
          ↑
      PVC와 Binding
          ↑
         Pod

동적 프로비저닝

Pod
 ↓
PVC 생성
 ↓
StorageClass 선택
 ↓
Provisioner가 Storage 생성
 ↓
PV 자동 생성
 ↓
PVC와 PV Binding
 ↓
Pod에 Mount

각 리소스의 역할을 한 문장으로 정리하면 다음과 같다.

리소스역할
VolumePod가 사용할 수 있는 스토리지 추상화
PV클러스터에 제공된 영구 스토리지 리소스
PVC사용자가 필요한 스토리지를 요청하는 리소스
StorageClass스토리지의 종류와 동적 생성 정책
CSI DriverKubernetes와 실제 스토리지 시스템을 연결

마무리

Kubernetes Storage를 이해할 때는 YAML 필드를 외우는 것보다 다음 관계를 먼저 이해하는 것이 중요하다.

Pod는 PVC를 요청하고, PVC는 조건에 맞는 PV와 연결되며, PV는 실제 스토리지를 추상화한다.

StorageClass가 없다면 관리자가 실제 스토리지와 PV를 미리 준비해야 한다. StorageClass와 Provisioner를 사용하면 PVC 요청에 따라 실제 스토리지와 PV를 자동으로 생성할 수 있다.

따라서 StorageClass는 단순한 스토리지 이름이 아니다. Kubernetes 환경에서 어떤 스토리지를, 어떤 정책으로, 언제 생성할 것인지 정의하는 프로비저닝 정책에 가깝다.

이번 내용을 다음 세 문장으로 압축할 수 있다.

  1. File, Block, Object Storage는 데이터를 저장하고 접근하는 방식이 다르다.
  2. PV는 제공되는 스토리지이고, PVC는 사용자의 스토리지 요청이다.
  3. StorageClass는 PVC 요청에 맞춰 스토리지를 동적으로 생성하는 방법과 정책을 정의한다.
profile
문제를 해결해보자 ✨

0개의 댓글