쿠버네티스에서 데이터의 영속성(Persistence)을 관리하는 것은 서비스의 안정성을 결정짓는 핵심 요소다. 파드는 언제든 죽을 수 있지만, 데이터는 살아남아야 하기 때문이다.
세 가지 주요 볼륨 타입의 핵심 메커니즘을 정리해보자.
1. emptyDir: 컨테이너 간 데이터 공유 (임시용)

- 용도: "동일한" 파드 내의 컨테이너들이 서로 데이터를 "주고받아야 할 때" = "공유하기 위해서" 사용한다.
- 생명 주기: 파드와 운명을 같이 한다. 파드가 생성될 때 비어있는 상태로 만들어지며, 파드가 삭제되면 데이터도 함께 증발한다.
- 즉, 최초 생성될 때 볼륨 내용이 비어있어서 emptyDir이라고 부르는것
- 그래서 일시적인 사용 목적에서 사용함
- YAML 포인트: 각 컨테이너는 서로 다른 mountPath를 가질 수 있지만, 동일한 volumes.name을 참조하여 같은 공간을 공유한다.
- 즉, 예시에서 두개의 컨테이너가 존재하는데,
- container1은 VolumeMounts의 mountPath를 /mount1으로 쓰는중
- container2은 VolumeMounts의 moutnPath를 /mount2으로 쓰는중
- 이 mountPath의 의미는 "각 컨테이너가 해당 Path를 써서 볼륨을 연결하겠다"는거는 맞음
- 하지만, 서로 Path가 달라도 결국에는 지정되는 볼륨의 이름(name)이 empty-dir임
- 이건 결국, 각 컨테이너마다 자신이 원하는 Path(경로)를 쓰고 있지만, 결국 한 볼륨(empty-dir)을 마운트하고 있는 것
- volumes의 속성으로 emptyDir: {}으로 지정하고 있는거 관찰가능
- 즉, 예시에서 두개의 컨테이너가 존재하는데,
2. hostPath: 노드 로컬 파일시스템 활용

- 용도: 한 호스트(=Node)에 Path를 볼륨으로써 사용 중. 워커 노드의 실제 디렉토리를 파드에 마운트한다.
- 특징: emptyDir과 다른 점은 파드가 죽어도 노드에 저장된 데이터는 유지된다. 하지만 한가지 큰 문제도 존재한다.
- Pod2가 죽어서 재생성이 될 때 꼭 해당 노드(Node1)에 재생성이 된다는 보장은 없다.
- 그래서 이렇게 파드가 다른 노드로 스케줄링되면 이전 노드의 데이터에 접근할 수 없다는 치명적인 단점이 있다.
- 물론, 굳이 방법을 찾는다면 쿠버네티스가 하는게 아닌 운영자가 수동작업을 할 수는 있음 (Node 추가시마다 별도의 마운트 기능을 사용)
- volumes의 속성으로 hostPath: ~로 지정하고 있는거 관찰가능
- 주의 사항: Pod가 생성되기 전에, 해당 노드 호스트에있는 Path(/node-v)는 사전에 생성되어 있어야 에러가 나지 않는다.
- 실무에서는 주로 노드 레벨의 로그 수집기나 시스템 도구에 한정적으로 사용한다.
3. PV & PVC: 인프라와 서비스의 분리 (영속성 표준)
실무에서 가장 중요한 개념이다. 파드에 영속성(=생명주기와 무관하게 영구보관) 있는 볼륨을 제공하기 위한 개념이다. 운영자(Admin)와 사용자(User)의 역할을 분리하여 스토리지 복잡성을 추상화한다.

- PV (Persistent Volume, 영구 볼륨)
- 외부 원격 사용(AWS, Git 등)의 형태도 있다.
- 즉, 운영자(Admin)가 준비한 실제 물리 저장소(AWS, NFS, Local 등)의 정의서다. 이걸 정의하고 연결을 하는 것이다.
- 용량(capacity)과 접근 모드(accessModes)를 명시한다.
- 근데 Pod는 PV에 바로 연결을 하지 않고, PVC라는 거를 먼저 통해서 PV와 연결이 된다.
- 왜 굳이? : 쿠버네티스는 User 영역과 Admin 영역으로 나눈 것임
- User(사용자)는 Pod 서비스를 만들고,
- Admin(쿠버네티스 담당 운영자)가 배포를 관리할 것
- 이 Admin이 PV를 만들어 놓으면, User는 이걸 사용하기 위해 PVC를 만들어야함
- 이 PVC(PersistentVolumeClaim)를 위한 YAML 내용을 보자.
- ReadWriteOnce (읽기 쓰기 모드 필요하다)
- storage: 1G (1GB 볼륨을 할당해달라)
- storageClassName: "" (공백? = 쿠버네티스가 현재 PV들 중에서 적절하게 선택함)
- 그리고 Pod를 만들 때 = volumes에 앞서 만들어놓은 PVC 이름(pvc-01)을 연결하는 것.
- 왜 굳이? : 쿠버네티스는 User 영역과 Admin 영역으로 나눈 것임

- PVC (Persistent Volume Claim, 영구 볼륨 요청)
- User(사용자)가 "나 1기가 용량의 읽기/쓰기 볼륨이 필요해"라고 요청하는 신청서다.
실습 전에 잠깐만 살펴보자
kind: PersistentVolume
....
....
specL
capacitiy:
storage: 1G
accessModes:
- ReadWriteOnce
local:
path: /node-v
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- {key: node, operator: In, values: [node1]}
- hostPath처럼 /node-v로 로컬 Path를 사용하는 것
- 결론적으로, 이 PV에 연결되는 파드들은 무조건 'node1'이라고 라벨링 되어있는 노드 위에만 만들어진다는 것
- 어떤 노드 위에 파드가 올라가건 이 노드에 지정되어있는 Path를 사용하면 좋을거 같지만,
- 그냥 파드를 생성할 때 무조건 node1 위에만 올라간다는 것이다.
- 데이터 영속적인 측면에서는 문제가 없기는 하다.
- 하지만, 로컬 타입은 실제로 많이 사용하지 않기 때문에 이해적인 측면에서 알아본 것
- 그리고 아까 storageClassName: "" (공백 = 쿠버네티스가 현재 PV들 중에서 적절하게 선택함)이라고 했었음
- 이거에 대한 쿠버네티스의 판단 근거는 무엇일까?
- capacity:
- accessModes:
- 이거에 대한 쿠버네티스의 판단 근거는 무엇일까?
실습에서 사용하는 로컬 타입 PV는 특정 노드에 파드를 고정시키는 nodeAffinity 설정을 포함한다. 이는 데이터 영속성은 보장하지만 클러스터의 유연한 자원 활용을 방해하므로 운영 환경에서는 신중해야 한다.
💡 꼬리 질문
"만약 PVC를 통해 PV를 할당받아 사용하던 중 파드를 삭제하면, 해당 PV에 저장된 데이터는 어떻게 될까? 이를 결정하는 설정값은 무엇인가?"
결론: PV의 persistentVolumeReclaimPolicy 설정에 따라 결정된다.
- Retain (보존): PVC가 삭제되어도 PV와 데이터는 그대로 유지된다. 관리자가 수동으로 데이터를 백업하거나 삭제해야 하며, 재사용하려면 수동 정리가 필요하다. 즉, 관리자가 수동으로 PV를 삭제할 때까지 재사용이 불가능하다.
- Delete (삭제): PVC 삭제 시 연결된 외부 스토리지(AWS EBS 등)와 데이터를 함께 삭제한다. 클라우드 환경의 기본값인 경우가 많다.
- Recycle (재활용): 데이터를 모두 지우고(rm -rf) 다른 PVC가 쓸 수 있도록 초기화한다. (현재는 권장되지 않으며 점차 사라지는 추세다.)
실무에서는 데이터 보호를 위해 중요한 데이터는 Retain 정책을, 임시 작업이나 테스트용은 Delete 정책을 주로 사용한다.
쿠버네티스에서 데이터가 어디에 살고 어떻게 죽는지를 이해하는 것이 이번 실습의 전부다.
1. emptyDir: 파드 내 컨테이너 간 데이터 공유

apiVersion: v1
kind: Pod
metadata:
name: pod-volume-1
spec:
containers:
- name: container1
image: kubetm/init
volumeMounts:
- name: empty-dir
mountPath: /mount1
- name: container2
image: kubetm/init
volumeMounts:
- name: empty-dir
mountPath: /mount2
volumes:
- name : empty-dir
emptyDir: {}
- 실습 구성: 하나의 파드 안에 container1과 container2를 생성하고, 동일한 empty-dir 볼륨을 각각 /mount1과 /mount2 경로에 마운트한다.
ls
mount | grep mount1
cd mount1
echo "file context" >> file.txt
ls
cd mount2
ls
cat file.txt
- 데이터 공유 확인: container1의 /mount1에 파일을 생성하면, container2의 /mount2에서도 동일한 파일과 내용이 실시간으로 확인된다.
- 휘발성 확인: 파드를 삭제한 후 다시 생성하면, 볼륨은 다시 비어있는 상태가 된다. 이는 emptyDir이 파드와 생명주기를 같이하며 일시적인 데이터 공유만을 목적으로 하기 때문이다.
2. hostPath: 노드의 특정 경로 공유 및 유지

apiVersion: v1
kind: Pod
metadata:
name: pod-volume-2
spec:
nodeSelector:
kubernetes.io/hostname: k8s-worker1
containers:
- name: container
image: kubetm/init
volumeMounts:
- name: host-path
mountPath: /mount1
volumes:
- name : host-path
hostPath:
path: /node-v
type: DirectoryOrCreate
---
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-3
spec:
nodeSelector:
kubernetes.io/hostname: k8s-worker1
containers:
- name: container
image: kubetm/init
volumeMounts:
- name: host-path
mountPath: /mount1
volumes:
- name : host-path
hostPath:
path: /node-v
type: DirectoryOrCreate
- 실습 구성: nodeSelector를 통해 k8s-worker1 노드에 두 개의 파드를 배치하고, 노드의 /node-v 디렉토리를 공유한다.
- Type 설정: DirectoryOrCreate 타입을 사용하면, 노드에 해당 디렉토리가 없더라도 파드 생성 시점에 자동으로 생성해주므로 사전에 경로를 만들 필요가 없다. 이전의 주의사항으로 알아봤던 아래의 내용을 위함이다.
- 주의 사항: Pod가 생성되기 전에, 해당 노드 호스트에있는 Path(/node-v)는 사전에 생성되어 있어야 에러가 나지 않는다.
- 데이터 영속성
- 첫 번째 파드에서 파일을 생성하면 노드의 실제 경로(/node-v)에 저장된다.
- 그니까, Pod가 생성될 때, nodeSelector에서 지정된 k8s-worker1이라는 노드에 Pod가 들어간 거고, k8s-worker1 노드의 로컬 디렉토리 경로가 "/node-v"인 것이다.
- 파드를 삭제하고 nodeSelector를 통해 이전 동일 노드를 딱 지정해서 다시 생성한다면, 데이터는 유지되지만,
- nodeSelector를 아예 삭제해서 지정을 안하고, 다른 노드(예: 노드2)에 생성되면 데이터가 보이지 않는 한계가 명확히 드러난다.
- 첫 번째 파드에서 파일을 생성하면 노드의 실제 경로(/node-v)에 저장된다.
3. PV & PVC: 관리와 사용의 분리 및 매칭 규칙 (상세코드)

- [Step1]: PV(운영자) 생성
- 세 종류의 PV를 준비한다.
- pv-01: 1G, ReadWriteOnce
- pv-02: 1G, ReadOnlyMany
- pv-03: 2G, ReadWriteOnce
- [Step2~3]: PVC(사용자) 바인딩 조건
- 쿠버네티스는 Capacity와 AccessMode를 기준으로 자동 연결한다.
- pvc-01(1G, ReadWriteOnce) → 요구사항과 일치하는 pv-01에 바인딩된다.
- pvc-02(1G, ReadOnlyMany) → ReadOnlyMany 모드를 가진 pv-02에 바인딩된다.
- pvc-03(3G, ReadWriteOnce) → 현재 3G를 만족하는 PV가 없으므로 Pending 상태로 대기한다.
- pvc-04(1G, ReadWriteOnce) → pv-01이 이미 사용 중이므로, 남은 것 중 최소 조건을 만족하는 pv-03(2G)에 바인딩된다. (자신보다 큰 용량에도 할당이 가능한 것을 보여준다.)
즉, 위의 단계에서 말하고 싶은 거는 PVC와 PV는 생성해놓고 연결은 어떻게 되냐인데,
capacity와 accessMode를 기준으로 연결된다는 것이다.
apiVersion: v1
kind: Pod
metadata:
name: pod-volume-5
spec:
containers:
- name: container
image: kubetm/init
volumeMounts:
- name: pvc-pv
mountPath: /mount3
volumes:
- name : pvc-pv
persistentVolumeClaim:
claimName: pvc-01
- [Step3]: 파드 연결 (Finish)
- 파드 생성 시 persistentVolumeClaim.claimName에 PVC 이름을 명시(pvc-01)하여 최종적으로 볼륨을 사용한다.
- 로컬 PV의 특징: 로컬 타입 PV는 nodeAffinity 설정을 통해 파드가 특정 노드에만 생성되도록 강제하여 데이터 영속성을 보장한다.
💡 꼬리 질문
Q: 실습에서 PV를 삭제하려 할 때, 해당 PV를 사용 중인 PVC가 남아있다면 어떤 현상이 발생하며, 이를 안전하게 삭제하는 순서는 어떻게 될까?
결론: 'Terminating' 상태에서 멈추며, 반드시 역순으로 삭제해야 한다.
- 현상: 쿠버네티스는 리소스 보호를 위해 사용 중인 PV를 강제로 지우지 않는다. PVC가 해당 PV를 물고 있으면 kubectl delete pv를 쳐도 상태가 Terminating으로 유지되며 실제 삭제가 보류된다.
- 안전한 삭제 순서:
- 1단계: 파드(Pod) 삭제 (볼륨 사용 중단)
- 2단계: PVC 삭제 (PV 요청 취소)
- 3단계: PV 삭제 (실제 리소스 해제)
- 예외 상황: 만약 순서가 꼬였다면, 남아있는 PVC를 먼저 삭제해야 보류 중이던 PV 삭제 작업이 자동으로 완료된다.
만약 아래와 같은 상황이면?


즉, 이건 Pod가 이 PVC를 마운트해서 잡고 있기(Lock) 때문에, 쿠버네티스가 강제 삭제를 멈추고 있는 것이다. 이 PVC가 파드에게 사용당하고 있기 때문이다.


- PVC 삭제됨: PV를 잡고 있던 연결고리가 사라짐.
- 정책이 Retain임: 데이터를 지우지 말라고 했으므로, PV와 데이터는 유지됨.
- 결과 (Released): "연결은 끊겼지만(Free), 데이터는 더러운(Dirty) 상태. 즉, PV 안에 이전 사용자의 데이터가 남아있다. 이걸 관리자(사람)가 직접 확인해서 지우든 백업하든 조치하기 전까지는, 안전을 위해 봉인(Lock)해 두겠다."
- 조치: 이 PV를 다시 쓰고 싶다면, 관리자가 직접 claimRef 정보를 삭제(Edit)하거나, PV를 지우고 재생성해야 비로소 Available로 돌아간다.
위 학습용 정리 내용 및 사진 자료는 "인프런_대세는 쿠버네티스(https://inf.run/Lv5RV)" 강의를 소스로 작성하였습니다.
'Cloud Native > Kubernetes' 카테고리의 다른 글
| 5. Namespace, ResourceQuota, LimitRange (0) | 2026.01.18 |
|---|---|
| 4. ConfigMap, Secret - Env, Mount (0) | 2026.01.18 |
| 2. Service - ClusterIP, NodePort, LoadBalancer (0) | 2026.01.16 |
| 1. Pod - Container, Label, NodeSchedule (1) | 2026.01.15 |
| 5. 쿠버네티스 클러스터의 논리적 아키텍처와 객체 간 유기적 관계망의 이해 (0) | 2026.01.15 |