[Kubernetes] PV와 PVC란 무엇일까?

굿굿·2026년 5월 27일

CI/CD

목록 보기
58/73

Kubernetes에서 Pod는 기본적으로 언제든지 사라질 수 있는 존재다.

Pod가 죽었다가 다시 생성되면 내부 파일도 같이 사라질 수 있다.

예를 들어 MySQL Pod를 띄웠다고 해보자.

MySQL Pod 안에 데이터 저장
        ↓
Pod 삭제
        ↓
데이터도 같이 사라질 수 있음

이러면 데이터베이스를 Kubernetes에서 운영할 수 없다.

그래서 Kubernetes에서는 Pod와 별도로 데이터를 저장할 공간이 필요하다.

이때 나오는 개념이 바로 PV와 PVC다.

PV  = PersistentVolume
PVC = PersistentVolumeClaim

1. 먼저 Volume이 왜 필요할까?

Pod 안의 컨테이너는 기본적으로 일회성에 가깝다.

컨테이너 안에 파일을 저장할 수는 있지만, 컨테이너가 재시작되거나 Pod가 삭제되면 데이터가 사라질 수 있다.

예를 들어 게시판 서버가 있다고 해보자.

게시글 이미지 업로드
로그 파일 저장
DB 데이터 저장

이런 데이터는 Pod가 사라져도 유지되어야 한다.

그래서 Kubernetes에서는 Pod 외부에 저장 공간을 붙여서 사용한다.

Pod
 ↓
Volume
 ↓
외부 저장 공간

이 저장 공간을 Kubernetes 방식으로 관리하기 위해 PV와 PVC를 사용한다.


2. PV란?

PV는 PersistentVolume의 약자다.

Persistent는 “지속되는”이라는 뜻이고, Volume은 “저장 공간”이라는 뜻이다.

즉 PV는 Kubernetes 클러스터 안에 등록된 실제 저장 공간이다.

PV = 클러스터에 준비된 실제 저장소

예를 들어 이런 것들이 PV가 될 수 있다.

NFS 저장소
hostPath
AWS EBS
GCP Persistent Disk
Azure Disk
Ceph
Longhorn

즉 PV는 “어디에 실제 데이터가 저장되는가”와 관련이 있다.

예를 들면 다음과 같다.

이 PV는 10Gi 용량이고
ReadWriteOnce 방식으로 접근 가능하며
실제 데이터는 /mnt/data에 저장된다

PV YAML 예시는 다음과 같다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mnt/data

이 YAML은 이런 뜻이다.

my-pv라는 PV를 만든다
용량은 1Gi다
접근 방식은 ReadWriteOnce다
실제 저장 위치는 노드의 /mnt/data다

3. PVC란?

PVC는 PersistentVolumeClaim의 약자다.

Claim은 “요청하다”, “청구하다”라는 뜻이다.

즉 PVC는 Pod가 사용할 저장 공간을 Kubernetes에게 요청하는 것이다.

PVC = 저장 공간 사용 요청서

Pod가 PV를 직접 고르는 것이 아니라, PVC를 통해 이렇게 요청한다.

저 1Gi 정도 저장 공간이 필요해요.
ReadWriteOnce 방식이면 됩니다.

PVC YAML 예시는 다음과 같다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

이 YAML은 이런 뜻이다.

my-pvc라는 PVC를 만든다
1Gi 저장 공간을 요청한다
ReadWriteOnce 방식의 볼륨을 원한다

4. PV와 PVC 관계

PV와 PVC의 관계는 “집”과 “입주 신청서”로 비유하면 쉽다.

PV  = 실제 집
PVC = 집을 빌리고 싶다는 신청서
Pod = 그 집에 들어가서 사는 사람

예를 들어 클러스터에 이런 PV가 있다고 해보자.

PV: 1Gi 저장 공간

그리고 PVC가 이렇게 요청한다.

PVC: 1Gi 저장 공간 주세요

Kubernetes는 조건이 맞는 PV와 PVC를 연결한다.

PV ↔ PVC 바인딩

그다음 Pod는 PVC를 사용한다.

Pod → PVC → PV → 실제 저장소

중요한 점은 Pod가 PV를 직접 쓰는 게 아니라는 것이다.

Pod는 PVC를 참조한다.


5. 전체 구조

PV, PVC, Pod의 관계를 그림으로 보면 이렇다.

Pod
 |
 | volumeMounts
 v
PVC
 |
 | bound
 v
PV
 |
 v
실제 저장 공간

조금 더 풀면:

1. 관리자가 PV를 만든다
2. 사용자가 PVC로 저장 공간을 요청한다
3. Kubernetes가 조건에 맞는 PV와 PVC를 연결한다
4. Pod가 PVC를 mount해서 사용한다
5. 데이터는 PV가 가리키는 실제 저장소에 저장된다

6. Pod에서 PVC 사용하기

PVC를 만든 뒤에는 Pod에서 이 PVC를 사용해야 한다.

예시는 다음과 같다.

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

여기서 중요한 부분은 두 군데다.

첫 번째는 volumes다.

volumes:
  - name: my-storage
    persistentVolumeClaim:
      claimName: my-pvc

이 뜻은:

my-pvc라는 PVC를 my-storage라는 이름의 볼륨으로 사용하겠다

두 번째는 volumeMounts다.

volumeMounts:
  - name: my-storage
    mountPath: /usr/share/nginx/html

이 뜻은:

my-storage 볼륨을 컨테이너 안의 /usr/share/nginx/html 경로에 붙이겠다

즉 전체적으로 보면:

PVC로 받은 저장 공간을
컨테이너 내부의 /usr/share/nginx/html 경로에 연결한다

7. mountPath란?

mountPath는 컨테이너 안에서 볼륨이 붙는 위치다.

예를 들어:

mountPath: /data

라고 하면 컨테이너 내부의 /data 경로가 외부 저장 공간과 연결된다.

컨테이너 내부 /data
        ↓
PVC
        ↓
PV
        ↓
실제 저장소

그래서 컨테이너 안에서 /data/test.txt 파일을 만들면, 그 파일은 실제로 PV가 가리키는 저장소에 저장된다.


8. accessModes란?

PV와 PVC에서 자주 보이는 설정이 있다.

accessModes:
  - ReadWriteOnce

accessModes는 볼륨을 어떤 방식으로 접근할 수 있는지를 의미한다.

대표적인 값은 다음과 같다.

ReadWriteOnce
ReadOnlyMany
ReadWriteMany

각각의 의미는 다음과 같다.

ReadWriteOnce
→ 하나의 노드에서 읽기/쓰기 가능

ReadOnlyMany
→ 여러 노드에서 읽기 전용으로 접근 가능

ReadWriteMany
→ 여러 노드에서 읽기/쓰기 가능

가장 자주 보는 것은 ReadWriteOnce다.

ReadWriteOnce = 보통 하나의 노드에서만 쓰기 가능

주의할 점은 “하나의 Pod만 가능”이라는 뜻이 아니라, 기본 의미는 하나의 노드에서 읽기/쓰기 가능이라는 것이다.


9. Reclaim Policy란?

PV에는 persistentVolumeReclaimPolicy라는 설정이 있다.

이건 PVC가 삭제되었을 때 PV를 어떻게 처리할지 정하는 정책이다.

대표적인 값은 다음과 같다.

Retain
Delete
Recycle

요즘은 주로 Retain과 Delete를 본다.

Retain
→ PVC가 삭제되어도 PV와 실제 데이터는 남겨둠

Delete
→ PVC가 삭제되면 PV와 실제 저장소도 삭제

Recycle
→ 오래된 방식, 거의 사용하지 않음

예를 들어 중요한 DB 데이터라면 함부로 삭제되면 안 된다.

그럴 때는 Retain이 더 안전할 수 있다.

persistentVolumeReclaimPolicy: Retain

뜻은:

PVC가 사라져도 실제 데이터는 보존하겠다

10. StorageClass란?

PV와 PVC를 공부하다 보면 StorageClass도 같이 나온다.

StorageClass는 쉽게 말하면 PV를 자동으로 만들어주는 방식이다.

원래는 관리자가 PV를 미리 만들어야 했다.

관리자: PV 미리 생성
사용자: PVC 생성
Kubernetes: 맞는 PV와 PVC 연결

이 방식을 정적 프로비저닝이라고 한다.

그런데 매번 PV를 직접 만드는 것은 귀찮다.

그래서 StorageClass를 사용하면 PVC를 만들 때 필요한 PV가 자동으로 생성될 수 있다.

사용자: PVC 생성
Kubernetes: StorageClass를 보고 PV 자동 생성

이걸 동적 프로비저닝이라고 한다.

Static Provisioning
→ PV를 미리 만들어둠

Dynamic Provisioning
→ PVC 요청에 따라 PV를 자동 생성

예를 들어 클라우드 환경에서는 PVC만 만들면 AWS EBS 같은 디스크가 자동으로 생성될 수 있다.


11. PV와 PVC 상태 확인하기

PV 확인:

kubectl get pv

PVC 확인:

kubectl get pvc

특정 PVC 자세히 보기:

kubectl describe pvc my-pvc

특정 PV 자세히 보기:

kubectl describe pv my-pv

정상적으로 연결되면 PVC 상태가 Bound로 나온다.

NAME      STATUS   VOLUME   CAPACITY
my-pvc    Bound    my-pv    1Gi

여기서 Bound는 PV와 PVC가 연결되었다는 뜻이다.


12. 자주 만나는 상태

PVC를 조회하면 상태가 여러 가지로 나올 수 있다.

Pending
Bound
Lost

대표적으로 중요한 것은 Pending과 Bound다.

Pending
→ 아직 조건에 맞는 PV를 찾지 못함

Bound
→ PV와 PVC가 정상적으로 연결됨

PVC가 계속 Pending이라면 보통 이런 문제를 의심할 수 있다.

요청한 용량에 맞는 PV가 없음
accessModes가 맞지 않음
storageClassName이 맞지 않음
동적 프로비저닝이 동작하지 않음

13. hostPath PV 예시

실습에서는 hostPath를 자주 쓴다.

hostPath는 노드의 특정 경로를 Pod에 연결하는 방식이다.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: hostpath-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mnt/data

이 PV는 노드의 /mnt/data 경로를 저장소로 사용한다.

하지만 hostPath는 운영 환경에서는 조심해야 한다.

왜냐하면 특정 노드의 로컬 경로에 의존하기 때문이다.

Pod가 다른 노드로 이동하면 같은 데이터를 못 볼 수 있음
노드가 장애 나면 데이터 접근이 어려움

그래서 운영에서는 보통 NFS, 클라우드 디스크, 분산 스토리지 등을 사용한다.


14. PV/PVC를 왜 이렇게 나눴을까?

처음 보면 그냥 Pod에서 바로 저장소를 지정하면 될 것 같다.

그런데 Kubernetes는 PV와 PVC를 나눴다.

이유는 역할 분리 때문이다.

관리자
→ 실제 저장소를 준비한다

개발자 또는 사용자
→ 필요한 저장소를 요청한다

즉 개발자는 실제 저장소가 NFS인지, EBS인지, Ceph인지 자세히 몰라도 된다.

그냥 PVC로 이렇게 요청하면 된다.

1Gi 저장 공간 주세요.
읽고 쓸 수 있어야 합니다.

그러면 Kubernetes가 조건에 맞는 PV를 연결해준다.

이 구조 덕분에 애플리케이션 YAML은 저장소 구현 방식에서 조금 더 독립적일 수 있다.


15. 전체 예시 한 번에 보기

PV 생성:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: /mnt/data

PVC 생성:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

Pod에서 PVC 사용:

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

적용 순서는 보통 다음과 같다.

kubectl apply -f pv.yaml
kubectl apply -f pvc.yaml
kubectl apply -f pod.yaml

확인:

kubectl get pv
kubectl get pvc
kubectl get pod

16. 헷갈리기 쉬운 포인트

Pod는 PV를 직접 쓰지 않는다

Pod는 보통 PVC를 참조한다.

Pod → PVC → PV

PVC는 요청서다

PVC 자체가 저장 공간은 아니다.

PVC = 저장 공간 주세요

PV는 실제 저장 공간이다

PV는 실제 저장소와 연결된 클러스터 리소스다.

PV = 여기 저장 공간 있습니다

Bound가 되어야 사용 가능하다

PVC가 Pending이면 아직 저장 공간을 받지 못한 상태다.

PVC Pending = 아직 연결 안 됨
PVC Bound = 연결 완료

StorageClass가 있으면 PV를 자동으로 만들 수 있다

PVC만 만들어도 StorageClass를 통해 PV가 자동 생성될 수 있다.

PVC 요청
  ↓
StorageClass
  ↓
PV 자동 생성

17. 정리

PV와 PVC는 Kubernetes에서 데이터를 유지하기 위한 핵심 개념이다.

Pod는 사라질 수 있지만 데이터는 유지되어야 한다.

그래서 Pod와 별도의 저장 공간을 연결한다.

정리하면 다음과 같다.

PV
→ 클러스터에 준비된 실제 저장 공간

PVC
→ 사용자가 저장 공간을 요청하는 리소스

Pod
→ PVC를 참조해서 저장 공간을 사용

StorageClass
→ PVC 요청에 따라 PV를 자동 생성하는 방식

Bound
→ PV와 PVC가 연결된 상태

한 줄로 정리하면 이렇다.

PV는 실제 저장 공간이고, PVC는 그 저장 공간을 쓰겠다는 요청서다.

조금 더 Kubernetes스럽게 말하면:

Pod는 PVC를 통해 PV를 사용하고, PV는 실제 스토리지와 연결된다.

즉 전체 구조는 이렇게 기억하면 된다.

Pod → PVC → PV → 실제 저장소
profile
https://greenapple0101.github.io/

0개의 댓글