본문 바로가기

k8s

8. Volume - emptyDir | hostPath | PV/PVC

728x90

1. emptyDir : 컨테이너들 끼리 데이터를 공유하기 위해 볼륨을 사용, 최초에 Volume 내부는 비어있기에 emptyDir 이라 부름.

-> Pod 생성시 만들어지고, 삭제시 없어진다. 그렇기 때문에 일시적으로만 존재해야하는 데이터를 저장하는 것이 바람직함.

요약 : 같은 Pod 안의 여러 Container가 같이 쓰는 임시 저장공간

apiVersion: v1
kind: Pod
metadata:
  name: pod-volume-1
spec:
  containers:
  - name: container1
    image: kubetm/init
    ## 2. 생성한 Volume을 container1 과 container2에 각각 연결(mount) 하는 작업
    volumeMounts:
    - name: empty-dir
      mountPath: /mount1
  - name: container2
    image: kubetm/init
    ## 2. 생성한 Volume을 container1 과 container2에 각각 연결(mount) 하는 작업
    volumeMounts:
    - name: empty-dir
      mountPath: /mount2
  ## 1. Volume을 하나 생성하는 부분
  
  volumes: 
  - name : empty-dir
    emptyDir: {}
    
##########################
[구조]
Pod
 ├─ container1
 │    └─ /mount1
 │
 ├─ container2
 │    └─ /mount2
 │
 └─ emptyDir Volume (공유 저장공간)

실제로는:
container1:/mount1
        ↕ (같은 공간)
container2:/mount2

이렇게 연결이 되는 구조로,
container1 에서 파일 생성시, container2 에서 바로 확인 가능
#########################

 

생성 시점 : Pod 가 생성될 때.

삭제 시점 : Pod 가 삭제될 때.

공유 범위 : 같은 Pod 내부의 Container 끼리 가능.

영속성 : 휘발성이므로 영속성은 없음.

저장 위치 : Node의 디스크 또는 메모

 

※ 휘발성 공간이므로, DB 저장용이나, 영구파일은 이 곳에 저장하면 안 된다.

※ 캐시/임시파일/컨테이너간 데이터 전달 시에만 사용.

 

2. hostPath : Pod 들이 올라가 있는 WorkerNode의 실제 경로(path)를 Volume으로써 사용

- 테스트 용도로 임시적으로 저장할 Volume이 필요할 때 사용

- HostPath 볼륨에는 보안 위험이 있기 때문에 운영환경에서는 가능하면 HostPath를 사용하지 않는 것을 권고.

- type 옵션:

  •     DirectoryOrCreate : 실제 경로가 없다면 생성
  •     Directory : 실제로 경로가 있어야 함
  •     FileOrCreate : 실제경로에 파일이 없다면 생성
  •     File : 실제로 파일 있어야 함.

-> 장점 : Pod 들이 죽어도 Volume이 사라지지 않음

-> 단점 : 스케줄러가 보기에 자원이 모자라 보이는 기존 노드가 아닌 다른 노드에 pod를 생성하는 경우, 혹은 Node 자체에 장애가 생겨 별도의 Node에 Pod를 만드는 경우에는 기존의 Volume을 찾아갈 수 없다. --> Node 추가시마다 Mount를 걸어주면 된다.

다만 이 방법은 linux system의 별도 mount 기술을 사용해야해서 실수를 만들 가능성이 높고,

사전에 해당 Node에 대한 경로가 필요하다.

apiVersion: v1
kind: Pod
metadata:
  name: pod-volume-2
spec:
  nodeSelector:
    kubernetes.io/hostname: k8s-worker1
  containers:
  - name: container
    image: kubetm/init
    volumeMounts:
      ## 위에서 선언한 WorkerNode k8s-worker1의 /node-v 디렉토리를
      ## Pod 내부 /mount1에 연결해라 라는 의미.
    - 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

 

[현재 구조]

/node-v
   ├── hello.txt
   └── data.log

        ↑ 공유

--------------------------------

[pod-volume-2]
/mount1

[pod-volume-3]
/mount1

 

저장 위치 : NodeSelector에서 선언한 Node의 실제 디스크

Pod 삭제 시 : 데이터가 유지 됨

여러 Pod 공유 : 가능

Node 의존성: emptyDir보다 훨씬 높음

운영 사용 : 매우 조심

 

hostPath의 특징

- Node 종속적

- 보안 위험이 큼

 

 

3. PV / PVC

* 생성시 [PV -> PVC -> Pod] 순으로, 삭제시 [Pod -> PVC -> PV] 순으로 삭제할 것!!!!!!

PV는 k8s admin 관점의 영역이고, PVC는 Pod 서비스 담당자(e.g 개발자) 영역이라고 보면 된다.

우선은 Pod가 사라지면 같이 사라지는 Volume에게 '영속성'을 부여하고자 하는 작업이라 생각하면 된다.

Pod가 곧바로 PV에 붙으면 되는거 아닌가 싶겠지만, PVC를 두어 구분하는 이유는 Volume을 연결하기 위한 속성이 다르기 때문.

PV를 사전에 정의하고 PVC를 통해서 "저 이런 Volume 제공 좀 해주세요" 하는거다.

그러면 PVC를 통해서 k8s가 PV를 연결하고, Pod 생성시 PVC를 마운트 한다.

 

- Pod에 영구적인 Volume을 할당하기 위한 리소스로 Pod -> PVC -> PV 순으로 연결한다.

- Pod 가 삭제됐다 재생성되어도, PVC/PV를 통해 지정된 Volume에 연결된다.

- PVC와 PV는 capacity와 accessMode를 기준으로 연결된다.

- PVC의 storageClassName:"" : PVC에 storageClassName을 사용하지 않고 PV에 연결하기 위한 설정

- PV의 local&nodeAffinity : 해당 PV에 연결된 Pod를 nodeAffinity에 지정한 Node에 스케줄링, 해당 Node를 Volume으로 사용

(이 때, local.path에 지정된 경로가 해당 Node에 존재해야 함.)

 

  • PV = 실제 저장소 자원 --> 관리자가 미리 만들어둔 저장소
  • PVC = 저장소를 요청하는 신청서
  • Pod = PVC를 통해 저장소 사용

 

저장소를 인프라와 애플리케이션에서 분리하자는 취지에서 나온 개념.

 

apiVersion: v1
## 관리자가 만든 저장공간
## 여기에 저장공간 선언해놨어
kind: PersistentVolume
metadata:
  name: pv-01
spec:
  capacity:
    # 1GB의 저장소를 제공하는 pv-01
    storage: 1G
  accessModes:
    # 하나의 Node에서 읽기/쓰기 가능
  - ReadWriteOnce
  local:
    # 실제 DISK 위치를 나타냄
    path: /node-v
  nodeAffinity:
    required:
	  # pv-01은 k8s-worker1 node에서만 사용이 가능해!
      nodeSelectorTerms:
      - matchExpressions:
        - {key: kubernetes.io/hostname, operator: In, values: [k8s-worker1]}
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-02
spec:
  capacity:
    storage: 1G
  accessModes:
  - ReadOnlyMany
  local:
    path: /node-v
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - {key: kubernetes.io/hostname, operator: In, values: [k8s-worker1]}
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-03
spec:
  capacity:
    storage: 2G
  accessModes:
  - ReadWriteOnce
  local:
    path: /node-v
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - {key: kubernetes.io/hostname, operator: In, values: [k8s-worker1]}
		

===

apiVersion: v1
## 나 이런 저장소 필요해요 선언
kind: PersistentVolumeClaim
metadata:
  # pvc 이름
  name: pvc-01
spec:
  # 원하는 접근방식
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
	  # 스토리지로 1GB 요청
      storage: 1G
  # 동적 프로비저닝을 안 쓰겠다.
  # 이 말은, 이미 만들어진 PV 중에서 찾을래!
  storageClassName: ""
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-02
spec:
  accessModes:
  - ReadOnlyMany
  resources:
    requests:
      storage: 1G
  storageClassName: ""
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-03
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 3G
  storageClassName: ""
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-04
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1G
  storageClassName: ""
 


===

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

 

AccessMode 이해하기

ReadWriteOnce (RWO)

하나의 Node에서 읽기/쓰기 가능
 

예:

  • worker1의 Pod들 사용 가능
  • worker2에서는 불가능

ReadOnlyMany (ROX)

여러 Pod가 읽기만 가능
 

쓰기 불가능.


ReadWriteMany (RWX)

여러 Pod가 동시에 읽기/쓰기 가능
 

보통 NFS 같은 공유스토리지에서 사용.

 

PVC와 PV가 연결되는 과정

쿠버네티스가 PVC 생성 시:

"조건 맞는 PV 있나?"
 

검색함.


pvc-01 경우

요청:

1G
ReadWriteOnce
 

PV 비교:

PV용량Mode결과
pv-01 1G RWO 가능
pv-02 1G ROX 불가
pv-03 2G RWO 가능

여기서 보통:

가장 적절한 PV
 

를 바인딩함.

대개 pv-01.


7. pvc-03가 실패하는 이유

 
requests:
  storage: 3G
 

근데 PV 최대가:

2G
 

뿐.

즉:

조건 만족하는 PV 없음
 

그래서:

Pending
 

상태가 됨.


8. pvc-04는?

 
1G
ReadWriteOnce
 

요청.

근데 이미 pv-01 이 pvc-01 에 바인딩됐다면?

남은 건:

PV상태
pv-02 ROX
pv-03 2G RWO

그러면 pv-03 에 연결될 가능성이 큼.


9. Pod에서 PVC 사용

이 부분이 실제 사용.

 
volumes:
- name : pvc-pv
  persistentVolumeClaim:
    claimName: pvc-01
 

의미:

pvc-01 을 마운트해서 쓰겠다
 

그리고:

 
volumeMounts:
- name: pvc-pv
  mountPath: /mount3
 

→ 컨테이너 내부 /mount3 에 연결.

즉:

컨테이너 /mount3
        ↓
PVC
        ↓
PV
        ↓
실제 디스크(/node-v)
 

이렇게 이어짐.

'k8s' 카테고리의 다른 글

7. Services - ClusterIP | NodePort | LoadBalancer  (0) 2026.05.11
6. kubectl [create | apply | get | describe | delete | exec]  (0) 2026.05.08
5. Node Schedule  (0) 2026.05.07
4. Service  (0) 2026.05.07
3. labels  (0) 2026.05.07