DevYGwan
Talos + Kubernetes 환경에서 LVM과 OpenEBS로 동적 스토리지 관리 구축 본문
저희는 talos OS 위에 K8s을 이용하여 온프렘 서버를 개발하고 있습니다. talos OS가 생소하신 분들도 있을 것 같은데, 간단하게 말해서 컨테이너 오케스트레이션(Kubernetes)에 최적화된 초경량 리눅스 운영체제입니다. 나중에 기회가 된다면 talos OS에 대해서 좀 더 자세히 설명하는 글을 만들도록 하겠습니다. 메인은 k8s 환경에서 서비스들을 관리하고 있다는 것입니다.
본론으로 돌아가서, 저는 이 k8s 환경에서 pod들을 관리하는 도중 디스크 관리 & PV(Persistent Volume)관리에 불편함을 느꼈습니다. 제가 불편함을 느낀 사항은 다음과 같습니다.
- talos의 Immutable 특성 때문에 디스크 추가 & 변경 시 talos machineconfig 파일을 매번 수정해줘야됨
- 업데이트 시, 디스크 탐지 순서 변화로 PV 경로가 깨지면 모든 서비스에 장애가 발생함
- 정적 PV 생성 시 매번 PV or SC(Storage class)를 만들어줘야함 (원하는 경로에 원하는 pv을 연결하기 위해서)
실제로,저희는 Talos MachineConfig로 사전에 디스크 파티션을 구성하고, 각 디스크에 대응하는 StorageClass를 생성해 Pod에 연결하는 방식으로 클러스터를 운영했습니다. 그러나 새로운 Pod를 추가할 때마다 MachineConfig를 다시 수정해야 했고, 그 과정에서 디스크 인식 순서가 바뀌어 기존 PV 경로가 깨지는 문제가 발생했습니다.
이처럼 디스크 관리가 어렵고, 설정 변경 후마다 재부팅이 필요한 점 때문에 Kubernetes에서 사용하는 PV를 어떻게 관리해야 할지 고민이 생겼습니다. 또한 온프렘 환경에서 4TB SSD 두 개를 사용하고 있어 RAID로 하나의 볼륨으로 묶어 관리하고 싶었고, 초기부터 큰 용량을 모두 할당하는 방식이 아니라 필요에 따라 점진적으로 확장하는 디스크 관리 방식이 필요했습니다.
이러한 요구사항을 효율적으로 처리하기 위해 저희는
- LVM
- Open EBS
도입하여 디스크를 동적으로 관리하기로 결정했습니다. 또한 디스크 레벨에서 암호화를 적용해 데이터 보안성을 강화하고, 노드 단위 장애나 디스크 교체 상황에서도 안정적으로 볼륨을 재구성할 수 있는 구조를 마련하는 것을 목표로 했습니다.
LVM & Open EBS 도입
LVM(Logical Volume Manager)이란 리눅스에서 물리 디스크를 묶고 추상화하여, 디스크 공간을 논리적으로 유연하게 관리할 수 있도록 해주는 기술입니다. 기본적으로 이해해야 할 핵심 구성요소는 다음과 같습니다.
- PV(Physical Volume): 실제 물리 디스크 또는 파티션을 LVM에서 사용할 수 있도록 초기화한 단위
- VG(Volume Group): 여러 개의 PV를 하나의 큰 스토리지 풀처럼 묶어 관리하는 단위
- LV(Logical Volume): VG에서 필요한 만큼 공간을 잘라 만들어 사용하는 논리 디스크로, 실제 디스크처럼 사용
이 구조 덕분에 물리 디스크가 여러 개라도 사용자가 필요에 따라 LV 크기를 확장하거나 축소할 수 있고, 새로운 디스크를 추가해 VG 용량을 늘릴 수도 있습니다. 또한 스냅샷 기능을 통해 특정 시점의 데이터를 보관할 수 있는 것도 LVM의 중요한 특징입니다.
실제로 디스크를 논리적인 volume으로 관리하기 때문에 더 유연하고 쉽게 관리할 수 있습니다.
1. PV 설정
lsblk
apk add lvm2 util-linux
pvcreate /dev/dm-2 /dev/dm-3
# pvs
PV VG Fmt Attr PSize PFree
/dev/dm-2 lvmvg lvm2 a-- <3.64t <2.80t
/dev/dm-3 lvmvg lvm2 a-- <3.64t <3.64t
- lsblk로 lvm으로 관리할 디스크를 확인합니다.
- lvm 처리를 위한 apk를 추가한 뒤, pvcreate 명령어로 원하는 디스크를 pv로 생성합니다.
- 그 후 pvs 명령어를 치면, 내가 원하는 디스크가 제대로 lvm의 pv로 설정된 것을 확인할 수 있습니다.
2. vg 설정
vgcreate lvmvg /dev/dm-2 /dev/dm-3
# vgs
VG #PV #LV #SN Attr VSize VFree
lvmvg 2 0 0 wz--n- <7.28t <7.28t
- 위에서 생성한 pv를 내가 원하는 vg명(lvmvg)과 함께 같은 vg로 묶습니다.
- “같은 VG로 묶는다”는 표현은 여러 개의 PV를 하나의 VG안에 포함시켜 하나의 큰 스토리지 풀로 만든다는 의미입니다.
- 이후에 추가적으로 vgextend 명령어로 언제든 유연하게 vg에 pv를 추가할 수 있습니다.
VG(Volume Group)은 볼륨을 물리적으로 묶는 RAID처럼 여러 디스크를 하나로 합치는 개념과 비슷한 느낌이지만, RAID가 하드웨어·블록 단에서 실제 데이터를 병합하고 중복 저장까지 처리하는 방식이라면, LVM의 VG는 그 위 레벨에서 여러 물리 디스크를 하나의 논리적 스토리지 풀처럼 취급해 유연하게 용량을 분할·확장할 수 있게 해주는 논리적 집합이라는 점에서 차이가 있습니다.
위의 작업까지는 k8s에서 작업하는 것이 아닌, os 레벨에서 디스크에 설정하는 옵션입니다.
아래부터는 k8s에서 사용하기 위한 설정입니다.
3. OpenEBS의 LVM LocalPV 추가
helm repo add openebs-lvm https://openebs.github.io/lvm-localpv
helm repo update
helm install openebs-lvm openebs-lvm/lvm-localpv \
--namespace openebs \
--create-namespace
- OpenEBS의 LVM LocalPV(로컬 스토리지 플러그인) 설치
- k8s가 각 노드의 로컬 디스크를 자동으로 LVM 볼륨으로 만들어 쓰게 해주는 스토리지 플러그인
- 아래에서 더 자세히 설명드리도록 하겠습니다.
4. lv 설정
Kubernetes → OpenEBS → LVM(VG/LV) → 디스크(PV)
위에서 생성한 VG를 StorageClass와 연결해두면, Kubernetes에서 PVC가 생성될 때마다 OpenEBS가 해당 VG를 스토리지 풀로 사용하여 필요한 용량만큼 LV를 자동으로 생성하고 이를 PV로 제공하게 됩니다. 즉, 여러 디스크(PV)를 하나의 VG로 묶어 두기만 하면, 이후에는 Kubernetes의 PVC 요청에 따라 OpenEBS가 그 VG 내부에서 LV를 동적으로 생성해주는 구조가 완성됩니다.
OpenEBS CSI란
Kubernetes에서 노드 로컬 디스크를 기반으로 동적 스토리지를 제공하는 CSI 스토리지 솔루션입니다.
OpenEBS의 구성 방식은 여러 가지가 있으며 대표적으로
- LocalPV HostPath : 특정 디렉터리를 PV로 매핑 (사용자가 직접 경로를 제공)
- LocalPV Device : 디바이스 목록을 OpenEBS에 등록 (PVC 생성 시 자동으로 디바이스를 할당)
- LocalPV LVM : OpenEBS가 LVM을 관리(PVC 요청 시 자동으로 LV 생성)
- Mayastor : 완전한 분산 스토리지
기본적으로 OpenEBS는 로컬 디스크를 Kubernetes 방식으로 관리 가능하게 만드는 CSI입니다. 원래는 hostPath를 사용해서 디스크를 관리했습니다. 그러다보니 경로를 만들고, PV or SC를 사전에 미리 만들어서 작업해야 한다는 단점이 생겼습니다. (내가 원하는 경로를 파드에 연결하기 위해선)
그래서 저는 lvm을 사용해서 디스크를 관리하기로 결정했기 때문에 CSI 스토리지 솔루션으로 LocalPV LVM를 사용하기로 결정했습니다.
LocalPV LVM
OpenEBS LocalPV LVM(Local Persistent Volume – LVM)은 각 Kubernetes 노드의 로컬 디스크를 기반으로 LVM 볼륨을 동적으로 생성해 PV로 제공하는 CSI 드라이버입니다. 이의 특징은,
- OS 레벨에서 LVM을 직접 구성할 필요 없음
- CSI가 PV 필요할 때 LV를 자동으로 만들고 제거
- Talos 같은 Immutable OS에서도 LVM을 Kubernetes 레벨에서 운영할 수 있음
내부 동작방식을 간단히 설명드리자면,
PVC → StorageClass → LocalPV LVM Provisioner → LVMNode Driver → LV 생성
- PVC : 필요 용량 요청
- StorageClass : “LocalPV-LVM을 사용하세요”라고 지정 (+ 사용할 vg 지정)
- LVM Provisioner : 적절한 노드를 선택
- LVMNode Daemon : 해당 노드에서 lvcreate를 실행해 LV 생성
- PV(LV) : Pod가 실제로 쓰는 파일시스템 볼륨 생성
위와 같은 순서로 디스크를 관리합니다.
※ 구조
[ 물리 디스크 1 ] -- pvcreate --┐
├── VG(lvmvg) ← OpenEBS가 사용하는 풀
[ 물리 디스크 2 ] -- pvcreate --┘
PVC 요청 → OpenEBS → lvcreate → LV 생성 → Kubernetes PV 생성 → Pod에 마운트
※ 하는일
| 기능 | 설명 |
| LVM 기반 로컬 볼륨 관리 | 각 노드의 디스크를 LVM으로 묶고, 필요한 크기만큼 LV(Logical Volume)를 동적으로 생성 |
| Kubernetes와 연동 (CSI) | PVC를 생성하면, LVM LocalPV가 자동으로 LV를 만들어서 Pod에 마운트 |
| 퍼포먼스 최적화 | 외부 NAS나 NFS 없이, 로컬 디스크 I/O 성능 그대로 활용 |
| 노드 로컬 스토리지 모델 | 데이터는 해당 노드의 디스크에 저장 → Pod가 그 노드에 스케줄되어야 접근 가능 |
이를 사용했을 때의 장점을 저희 상황에서 설명드리자면,
- Talos MachineConfig 수정 불필요
- 디스크를 LVM용 PV로만 등록해두면, LV 생성·삭제·확장은 OpenEBS가 자동 처리합니다.
- PVC 확장 요청도 LVM CSI가 자동 반영하므로 Talos 설정을 다시 수정할 필요가 없습니다.
- 디스크 확장 용이
- 새 디스크 추가 후 pvcreate → vgextend만 수행하면 기존 VG에 쉽게 합칠 수 있습니다.
- VG 용량이 늘어나면 PVC에서도 즉시 추가 용량 사용이 가능합니다.
- 디스크 순서 변경 문제 해결
- Talos에서는 디바이스 이름(/dev/nvme0n1 → /dev/nvme1n1)이 재부팅·업그레이드·장치 추가 시 바뀌는 경우가 있습니다.
- Talos에서 디스크 이름이 바뀌어도, LVM은 PV를 UUID로 추적하므로 VG/LV 동작에 영향이 없습니다.
- 이로 인해 PV 경로 깨짐이나 MachineConfig 수정 같은 문제를 근본적으로 예방합니다.
- 디스크 관리 간편화
- 여러 디스크를 하나의 VG로 묶어 풀처럼 관리할 수 있어 StorageClass/PV를 디스크별로 만들 필요가 없습니다.
- 실질적인 볼륨 생성·확장·정책 관리는 k8s(LVM + OpenEBS)에서 이루어지므로 Talos의 불변성 제약과 충돌하지 않습니다.
등이 있습니다.
※ 결과
# lvs
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
pvc-22948b11-7b57-41d5-9caa-36e7cf3f53b0 lvmvg -wi-ao---- 10.00g
pvc-5eccd3cd-d307-48b1-a347-f01f218f8728 lvmvg -wi-ao---- 50.00g
pvc-870dc156-6538-4fac-8b7c-3d6aba4325e6 lvmvg -wi-ao---- 200.00g
pvc-8ee774c6-bc05-40f1-afa0-e0764d216ce8 lvmvg -wi-ao---- 20.00g
pvc-b084ffa1-2a29-46e1-a2bf-ea29cf933f44 lvmvg -wi-ao---- 10.00g
pvc-bc8d6a6f-a65b-4d24-9618-54b08877ed79 lvmvg -wi-ao---- 300.00g
pvc-c38b0c34-376c-409f-b9bf-27b67cfcb6f2 lvmvg -wi-ao---- 200.00g
pvc-ca579027-378f-4b12-9e49-936bcb96121f lvmvg -wi-ao---- 50.00g
pvc-d7aa9ecf-e94b-43fa-8e99-d2a3063bf7ec lvmvg -wi-a----- 20.00g
pvc-f6000a73-5087-4f08-ab52-d9ab4c51ba0c lvmvg -wi-ao---- 100.00g
# pvs
PV VG Fmt Attr PSize PFree
/dev/dm-2 lvmvg lvm2 a-- <3.64t 2.70t
/dev/dm-3 lvmvg lvm2 a-- <3.64t <3.64t
# vgs
VG #PV #LV #SN Attr VSize VFree
lvmvg 2 10 0 wz--n- <7.28t <6.34t
보시는 바와 같이, 동적으로 lv가 생성되어 pod의 UUID로 매핑되어 관리되고 있는 것을 확인할 수 있었습니다.
정리
이번에는 onprem 환경에서 디스크를 어떻게하면 효율적으로 관리할 수 있는지를 고민해봤습니다. 간단하게 흐름을 도식화하자면,
이렇게 표현할 수 있습니다. OpenEBS LVM LocalPV는 LVM의 논리 볼륨 관리 기능을 그대로 활용하면서, Kubernetes의 PVC 요청에 따라 자동으로 LV(Logical Volume)를 생성하고, 이를 PV(PersistentVolume)로 바인딩하여 Pod에 마운트합니다. 이 방식은 외부 스토리지(NFS, Ceph 등)를 구성하지 않아도 로컬 디스크의 고속 I/O 성능을 그대로 유지할 수 있다는 점이 큰 장점입니다.
특히, 여러 개의 디스크를 하나의 Volume Group으로 통합해두면, 노드 내에서 스토리지 용량을 유연하게 분배할 수 있으며, 개별 Pod가 필요한 만큼의 용량만큼 LVM LV를 자동으로 할당받을 수 있습니다. 이로써 Kubernetes 환경에서도 LVM의 유연한 용량 확장성과 OpenEBS의 동적 볼륨 관리 기능을 함께 활용할 수 있게 됩니다.
이밖에도, 이를 사용했을 때의 비즈니스 임팩트를 정리해보자면,
개발자 관점
- 운영 효율성 향상
- 디스크 확장, PV 생성, 스토리지 정책 변경 등 대부분의 작업이 Kubernetes 내부에서 자동화되기 때문에 운영 인력이 매번 Talos MachineConfig를 수정하거나 재부팅할 필요가 없습니다.
- 서비스 가용성 증가
- 디스크 이름 변경, PV 경로 깨짐 등 Talos 기반 시스템의 대표적인 장애 원인이 LVM+OpenEBS 구조에서 사라짐.
- 스토리지 확장 및 변경 시 노드 재부팅이 필요 없기 때문에 서비스 중단이 발생하지 않습니다.
- 스토리지 확장성 확보
- 디스크 추가 시 OS 재구성이 필요 없고, vgextend로 즉시 스토리지 용량을 확장할 수 있어 비즈니스 성장에 맞춰 빠르게 대응 가능합니다.
- 데이터 증가나 신규 서비스 출시 때 스토리지 제약이 줄어들어 확장 속도와 기민성이 향상됩니다.
- 인프라 변경 리스크 감소
- Talos의 불변성(Immutable OS) 특성으로 인해 자주 발생하던 “MachineConfig 수정 → 재부팅 → 예기치 않은 장애” 위험이 사라집니다.
- 스토리지 운영이 Kubernetes/LVM에서 일관되게 관리되어 예측 가능한 인프라 환경을 제공합니다.
- 하드웨어 비용 최적화
- 여러 디스크를 하나의 VG로 묶어 스토리지 효율성을 극대화할 수 있습니다.
- 노드 단위로 디스크를 유연하게 사용할 수 있어 기존 인프라의 활용도가 올라가고, 불필요한 신규 하드웨어 구매를 줄일 수 있습니다.
일반 사용자(고객) 관점
- 서비스가 멈추지 않는다
- 저장공간을 늘리거나 디스크 변경 시 서버 재부팅 없이 저장공간을 확장할 수 있기 때문에 서비스가 멈추지 않는다.
- 저장 공간을 마음대로 늘릴 수 있다
- 필요한 시점에 원하는 만큼 확장이 간편하게 가능하다.
- 여러 개의 디스크를 하나처럼 쓸 수 있다
- 하나의 대용량 디스크를 사서 사용하는 것이 아닌, 여러 작은 디스크를 하나의 논리적 단위로 묶어 사용하기 때문에 디스크의 가격적인 이점을 얻을 수 있다.
이 기술을 도입하면 서버 저장 공간이 자동으로 관리되고, 장애가 줄어들며, 서비스를 끄지 않고도 바로 확장할 수 있어서 전체적으로 회사가 더 안정적이고 효율적으로 운영됩니다.