
쿠버네티스의 데이터 저장 메커니즘을 알기 위해, Local Volume의 해결책으로 등장하는 Network Volume, PV와 PVC를 살펴보자.
Pod 내부의 각 컨테이너는 이미지에서 제공되는 고유하게 분리된 파일시스템을 가진다.
Node의 Local Storage를 사용하는 Pod의 Local Volume(저장 공간) 타입에는 대표적으로 emptyDir와 hostPath가 있다.
apiVersion: v1
kind: Pod
metadata:
name: emptydir-pod
spec:
containers:
- name: busybox
image: busybox # 디렉토리에 파일 작성 후 sleep
command: ["sh", "-c", "echo hi > /data/test.txt && sleep 3600"]
volumeMounts: # Pod의 mount 위치 지정
- name: shared-storage
mountPath: /data # Pod IP/data에서 확인
volumes:
- name: shared-storage
emptyDir: {}
apiVersion: v1
kind: Pod
metadata:
name: hostpath-pod
spec:
containers:
- name: busybox
image: busybox
command: ["sh", "-c", "echo hi > /mnt/data/test.txt && sleep 3600"]
volumeMounts: # Pod의 mount 위치 지정
- name: host-storage
mountPath: /mnt/data
volumes:
- name: host-storage
hostPath:
path: /data/k8s-data # Node의 로컬 파일 시스템 상 위치
type: DirectoryOrCreate # 디렉토리가 없으면 자동 생성
# data 확인
kubectl exec -it emptydir-pod -- cat /data/test.txt # emptyDir
kubectl exec -it hostpath-pod -- cat /mnt/data/test.txt # hostPath
Pod가 어떤 Node에서 실행될지 모르기 때문에 Network Volume이 필요하다.
Stateful Pod가 내부에서 특정 데이터를 보유해야 하거나 데이터를 Node 간에 공유하고 스케줄링 유연성을 보장하려면, 네트워크를 통해 접근 가능한 저장소가 필요하다.
volumeMounts(Pod 내 마운트 위치)를 지정 후 spec.volumes.nfs.path에 PATH를, spec.volumes.nfs.server에 NFS_SERVICE_IP를 작성하여 Pod에서 마운트한다. 위와 같은 과정으로 Network Volume을 사용하는 것은 Pod마다 NFS 정보를 반복 설정해야 하며, 동적 할당이 불가하기 때문에 추상화와 자동화 등을 제공하는 PersistentVolume(=PV)과 PersistentVolumeClaim(=PVC)을 이용한다.
동적으로 생성되고 제거되는 Pod들과 분리된 저장소를 추상화하여 사용하게 만들기 위해 등장한 개념
capacity: 스토리지 용량accessModes: 접근 방식ReadWriteOnce: 하나의 노드에서 읽기/쓰기ReadOnlyMany: 여러 노드에서 읽기만 가능ReadWriteMany: 여러 노드에서 읽기/쓰기 가능persistentVolumeReclaimPolicy: PVC 삭제 시 PV의 처리 방식Retain: PV의 데이터 보존Delete: PV와 실제 스토리지 삭제 (주로 동적 프로비저닝)Recycle: 기존 데이터 삭제 후 재사용 (거의 사용 안 함)resources.requests.storage)과 접근 방식(accessModes)을 정의한다.accessModes: 사용하고자 하는 PV의 accessModes와 동일한 옵션을 사용해야 바운딩이 가능하다requests: 사용을 원하는 용량 명시한다. storage: 사용하고자 하는 최소한의 크기로서 명시한 용량보다 큰 PV도 상관 없다.spec.containers.volumeMounts에 Pod 내 디렉토리 지정 후 volumes.hostPath를 PV 위치로 지정해서 진행한다.spec.containers.volumeMounts에 Pod 내부 디렉토리 경로 지정 후 volumes.persistentVolumeClaim을 PVC name으로 지정해서 진행한다.StorageObjectInUseProtection에 의해 PVC가 사용 중이면 삭제되지 않는다.1. NFS 서버를 Kubernetes 내부에 구성
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-server
spec:
replicas: 1
selector:
matchLabels:
app: nfs-server
template:
metadata:
labels:
app: nfs-server
spec:
containers:
- name: nfs # 이미 만들어진 공개 이미지 사용
image: itsthenetwork/nfs-server-alpine:latest
ports:
- name: nfs
containerPort: 2049
securityContext:
privileged: true # NFS 커널 모듈 사용을 위한 권한 필요
env:
- name: SHARED_DIRECTORY
value: /exports # 공유 디렉토리 경로 설정
---
apiVersion: v1
kind: Service
metadata:
name: nfs-service
spec:
selector:
app: nfs-server
ports:
- name: nfs
port: 2049
targetPort: 2049
clusterIP: None
2. PV 생성
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1Gi # 최대 1GiB까지 PVC에서 요청 가능
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs: # Headless DNS로 NFS Pod 직접 참조
server: nfs-server-0.nfs-service.default.svc.cluster.local
path: /exports/data # 실제 NFS 서버의 공유 디렉토리 경로
3. PVC 생성
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany # PV와 동일한 모드로 설정해야 바인딩 가능
resources:
requests:
storage: 500Mi # 최소 500Mi 요청
4. 실제 Pod에서 PVC 사용
apiVersion: v1
kind: Pod
metadata:
name: nfs-client
spec:
containers:
- name: app
image: busybox
command: ["sh", "-c", "echo hi > /mnt/nfs/hello.txt && sleep 3600"]
volumeMounts:
- name: nfs-vol
mountPath: /mnt/nfs # Pod 내에서 접근할 NFS 디렉토리 경로
volumes:
- name: nfs-vol
persistentVolumeClaim: # 이 PVC를 통해 PV와 연결
claimName: nfs-pvc