영구 볼륨을 일반적인 파일 시스템으로부터 어태치 하지 않고 블록 장치로부터 어태치할 수도 있다. PVC 의 spec.volumeMode: Block 으로 지정하고(기본값이 FileSystem 임), PVC 를 사용하는 Pod 에서는 컨테이너 템플릿의 volumeDevices 를 지정하면 된다.(파일시스템인 경우 volumeMounts 인 것과 대비됨)
단, 현재 로컬 머신에는 NFS 스토리지만 준비되어있기 때문에 블록 스토리지를 추가로 구성해줘야 한다. 블록 스토리지를 실습하기 위해서는 Longhorn을 사용하는 방법이 권장되지만, 맥북 리소스의 한계로 이전에 구축에 실패하였다. 따라서 이번에는 OpenEBS LocalPV-LVM/ZFS 방식으로 구축해본다. VM에 추가 가상 디스크를 구성하고, 각 노드에서 해당 디스크를 블록 장치로 사용하는 방식이다. 단, LocalPV 이기 때문에 클러스터 공유 스토리지가 아닌, 특정 노드의 로컬 디스크에 종속된 스토리지라서 노드 간에 데이터 공유가 안된다는 점이 유의하자.
1. 가상 머신에 블록 디스크 추가(모든 워커 노드)
각 워커 노드 머신의 전원을 종료(shutdown -h now)한 후, UTM 에서 디스크를 추가한다. 인터페이스는 VirtIO, 크기는 본인의 리소스를 고려하여 적절히 세팅한 후 저장한다.

이후 다시 워커 노드를 부팅 후, lsblk 명령어를 사용하여 추가된 디스크를 확인한다.
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
...
vdb 253:16 0 2G 0 disk
2. LVM(Logical Volume Manager)용 PV(Physical Volume) 생성(모든 워커 노드)
Logical Volume Manager 가 추가한 디스크를 사용할 수 있는 상태로 만드는 작업이다. 모든 워커 노드에서 아래 명령어를 입력한다.
# lvm2 도구 설치
$ sudo apt update && sudo apt install lvm2 -y
# 물리 볼륨 생성
$ sudo pvcreate /dev/vdb
Physical volume "/dev/vdb" successfully created.
아래 명령어로 PV를 조회한다. 위에에서 생성한 /dev/vdb 가 조회되면 된다.
$ sudo pvs
PV VG Fmt Attr PSize PFree
...
/dev/vdb lvm2 --- 2.00g 2.00g
3. VG(Volume Group) 생성(모든 워커 노드)
물리 볼륨(PV)들을 하나의 그룹으로 묶는다. VG 이름은 나중에 쿠버네티스 스토리지 클래스에서 그대로 사용하게 된다. 여기서는 lvmvg 이라고 지정했다. 모든 워커 노드에서 진행한다.
# /dev/vdb 물리 볼륨을 'lvmvg'라는 이름의 볼륨 그룹으로 생성한다.
$ sudo vgcreate lvmvg /dev/vdb
Volume group "lvmvg" successfully created
# 조회
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
lvmvg 1 0 0 wz--n- <2.00g <2.00g
4. LVM-LocalPV CSI 드라이버 설치(마스터 노드)
OpenEBS 의 LVM 연동 도구를 설치한다. 마스터 노드에서 실행한다. openebs 네임스페이스가 아닌 kube-system 네임스페이스 설치가 기본값인 듯 하다.
# LVM-LocalPV 오퍼레이터(Operator)와 관련 구성 요소를 쿠버네티스 클러스터에 배포한다.
$ kubectl apply -f https://openebs.github.io/charts/lvm-operator.yaml
아래 커맨드를 실행하여 필요한 리소스들이 생성되었는지 확인한다.
$ kubectl -n kube-system get statefulsets -l openebs.io/component-name
NAME READY AGE
openebs-lvm-controller 1/1 70m
$ kubectl -n kube-system get daemonsets -l openebs.io/component-name
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
openebs-lvm-node 2 2 2 2 2 <none> 70m
# openebs-lvm-controller 는 statefulset 이 관리하고, openebs-lvm-node 는 daemonset 이 관리한다.
$ kubectl -n kube-system get pods -l openebs.io/component-name
NAME READY STATUS RESTARTS AGE
openebs-lvm-controller-0 5/5 Running 0 72m
openebs-lvm-node-8fmwx 2/2 Running 0 72m
openebs-lvm-node-dgjbp 2/2 Running 0 72m
5. 스토리지 클래스 생성
아래 매니페스트를 이용하여 SC를 생성한다. 프로비저너로 위에서 설치한 OpenEBS 의 CSI 드라이버를 사용하기 때문에 동적 프로비저닝 기능이 이미 포함되어있다. volumeBindingMode: WaitForFirstConsumer 를 주어서 실제 파드가 노드에 스케쥴링된 후에야 동적으로 볼륨 바인딩이 일어날 수 있도록 한다. 이는 LocalPV 를 사용할 때 중요하다. 스토리지가 노드에 종속되어있기 때문에 실제로 파드가 노드에 배정되었을 때 그 노드의 lvmvg 에서 공간을 쪼개 할당할 수 있기 때문이다.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: sample-block-storageclass
provisioner: local.csi.openebs.io # 중요
parameters:
storage: "lvm"
volgroup: "lvmvg" # 미리 생성해두 Volume Group 명을 지정한다.
volumeBindingMode: WaitForFirstConsumer # 중요
allowVolumeExpansion: true
6. PVC 생성
아래 매니페스트를 이용하여 PVC를 생성한다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sample-block-pvc
spec:
storageClassName: sample-block-storageclass
volumeMode: Block # 중요
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 500Mi
7. 파드 생성
실제로 블록 장치를 볼륨으로 사용할 파드를 배포한다.
apiVersion: v1
kind: Pod
metadata:
name: sample-block-pod
spec:
containers:
- name: nginx-container
image: nginx:1.27
volumeDevices:
- name: nginx-pvc
devicePath: /dev/sample-block
volumes:
- name: nginx-pvc
persistentVolumeClaim:
claimName: sample-block-pvc
8. 동적 프로비저닝 확인
파드가 PVC 를 사용하는 시점에 동적으로 PV 가 생성되었는지 확인한다.
# PVC 가 BOUND 되었는지 확인
$ kubectl get pvc sample-block-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
sample-block-pvc Bound pvc-560cb363-b43c-498c-b397-309cd893cc6c 500Mi RWO sample-block-storageclass <unset> 90m
# PV 가 생성되었는지 확인
$ kubectl get pv pvc-560cb363-b43c-498c-b397-309cd893cc6c
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-560cb363-b43c-498c-b397-309cd893cc6c 500Mi RWO Delete Bound default/sample-block-pvc sample-block-storageclass <unset> 60m
# Pod 가 Running 중인지 확인
$ kubectl get pods sample-block-pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
sample-block-pod 1/1 Running 0 90m 10.244.2.83 worker02 <none> <none>
# Pod 내에 Block 장치가 연결되었는지 확인
$ kubectl exec -it sample-block-pod -- ls -l /dev/sample-block
brw------- 1 root root 252, 1 Feb 22 10:20 /dev/sample-block
'Kubernetes' 카테고리의 다른 글
| [Kubernetes] allowVolumeExpantion 으로 볼륨 확장하기 (0) | 2026.02.22 |
|---|---|
| [Kubernetes] volumeBindingMode 영구 볼륨 할당 타이밍 제어 (0) | 2026.02.18 |
| [Kubernetes] 영구 볼륨 동적 프로비저닝 (0) | 2026.02.16 |
| [Kubernetes] PersistentVolumeClaim 이해 (0) | 2026.02.16 |
| [Kubernetes] PersistentVolume 이해 (0) | 2026.02.11 |
