RHEL 중급 #2 LVM — PV/VG/LV, 스냅샷, 확장
기초 #6의 자동 파티셔닝에서 만난 /dev/mapper/rhel-root가 LVM이었습니다. 이번 글에서는 그 LVM을 직접 다뤄봅니다. PV / VG / LV의 구조를 먼저 잡고, 새 디스크를 붙여 LV를 확장하는 흐름, 스냅샷으로 백업 직전 상태를 잡는 방법, 그리고 thin provisioning과 RAID 옵션까지 순서대로 정리합니다.
RHEL 중급 시리즈에서 이번 글의 위치:
- #1 SELinux 입문 — Enforcing/Permissive, 라벨, 트러블슈팅
- #2 LVM — PV/VG/LV, 스냅샷, 확장 ← 이번 글
- #3 스토리지 심화 — Stratis, NFS, Samba
- #4 네트워킹 — NetworkManager (nmcli), bonding, teaming
- #5 로그 관리 — journald, rsyslog, log rotation
- #6 작업 스케줄링 — cron, systemd timer, at
- #7 컨테이너 입문 — Podman/Buildah/Skopeo (Docker와의 차이)
LVM이 푸는 문제 #
전통적인 파티션은 한 번 잡으면 크기가 고정됩니다. /home이 가득 찼는데 /var은 한가하다면? 디스크를 통째로 백업하고, 파티션 테이블을 새로 잡고, 복원하는 큰 작업이 필요합니다. 운영 머신은 이 동안 멈춰야 합니다.
LVM(Logical Volume Manager)은 물리 디스크와 파일시스템 사이에 한 층을 더 끼워서이 한계를 풉니다. 디스크가 가득 차면 새 디스크 한 장을 추가하고, 명령 두세 줄로 LV를 늘리고, 파일시스템을 그대로 확장합니다. 다운타임 없이.
/dev/sdb1 /dev/sdc1 /dev/sdd1 ← 물리 파티션
│ │ │
▼ ▼ ▼
[PV] [PV] [PV] ← Physical Volume
└───────────┼───────────┘
▼
┌─────────────┐
│ VG │ ← Volume Group (풀)
│ data_vg │
└──┬───┬───┬──┘
│ │ │
▼ ▼ ▼
[LV] [LV] [LV] ← Logical Volume
│ │ │
▼ ▼ ▼
xfs ext4 swap ← 파일시스템 / swap
│ │
▼ ▼
/data /home세 층의 역할:
| 층 | 약자 | 의미 |
|---|---|---|
| Physical Volume | PV | 디스크 / 파티션 한 장을 LVM 용으로 표시한 것 |
| Volume Group | VG | PV 여러 장을 묶은 풀. “사용 가능한 저장소 풀” |
| Logical Volume | LV | VG에서 잘라낸 논리 볼륨. 여기에 파일시스템을 올림 |
핵심은 VG가 추상화 층 이라는 것. VG의 총 용량은 PV들의 합이고, LV는 그 안에서 자유롭게 잘라 쓰며, 디스크를 추가하면 VG가 커지고, LV를 늘리면 거기서 가져옵니다.
직접 만들어보기 — PV → VG → LV #
기초 #6에서 추가한 빈 디스크 /dev/vdb를 LVM으로 다시 잡아보겠습니다.
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
vda ... 40G 0 disk
├─vda1 ...
└─vda2 ...
├─rhel-root ...
└─rhel-swap ...
vdb 252:16 0 20G 0 disk ← 빈 디스크 한 장1) PV 생성 — pvcreate
#
$ sudo pvcreate /dev/vdb
Physical volume "/dev/vdb" successfully created.
$ sudo pvs
PV VG Fmt Attr PSize PFree
/dev/vda2 rhel lvm2 a-- 39.00g 0
/dev/vdb lvm2 --- 20.00g 20.00gpvs는 PV 한 줄 요약, 더 자세히 보려면 pvdisplay /dev/vdb. 디스크 통째로 PV로 잡았는데, 파티션 단위로도 가능 (pvcreate /dev/vdb1).
2) VG 생성 — vgcreate
#
$ sudo vgcreate data_vg /dev/vdb
Volume group "data_vg" successfully created
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
data_vg 1 0 0 wz--n- <20.00g <20.00g
rhel 1 2 0 wz--n- <39.00g 0data_vg라는 이름의 새 VG가 만들어졌고, PV 한 장(/dev/vdb)을 품고 있습니다. 이름 규칙은 자유롭지만 용도가 드러나는 이름(data_vg, app_vg, db_vg)이 운영에 좋습니다.
3) LV 생성 — lvcreate
#
VG에서 LV를 잘라냅니다. 일부만, 또는 전체를.
# 10GB짜리 LV 하나
$ sudo lvcreate -L 10G -n data_lv data_vg
Logical volume "data_lv" created.
$ sudo lvs
LV VG Attr LSize ...
data_lv data_vg -wi-a----- 10.00g
home rhel -wi-ao---- <10.00g
root rhel -wi-ao---- 25.00g
swap rhel -wi-ao---- 4.00g옵션 풀이:
-L 10G— 절대 크기.-l 100%FREE로 VG의 남은 공간 전부,-l 50%VG로 VG 전체의 50% 같은 비율 지정도 가능.-n data_lv— LV 이름.- 마지막
data_vg— 어느 VG에서 잘라낼지.
4) 파일시스템 만들고 마운트 #
LV는 일반 블록 장치처럼 /dev/<VG>/<LV> 또는 /dev/mapper/<VG>-<LV>로 접근합니다.
$ sudo mkfs.xfs /dev/data_vg/data_lv
$ sudo mkdir -p /data
$ sudo mount /dev/data_vg/data_lv /data
$ df -hT /data
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/data_vg-data_lv xfs 10G 175M 10G 1% /data기초 #6의 흐름과 동일하게 /etc/fstab에 UUID로 영구 등록:
$ sudo blkid /dev/data_vg/data_lv
/dev/mapper/data_vg-data_lv: UUID="..." TYPE="xfs"UUID=... /data xfs defaults,nofail 0 0여기까지가 새 디스크를 LVM으로 운영하는 표준 흐름 입니다. 한 번 익혀두면 같은 패턴이 반복됩니다.
LV 확장 — 운영의 일상 #
LVM의 진짜 가치는 여기서 드러납니다. /data가 80% 찼다고 가정해봅시다.
1) 새 PV 추가 #
새 디스크 /dev/vdc(10GB)를 머신에 붙였다고 합시다.
$ sudo pvcreate /dev/vdc
Physical volume "/dev/vdc" successfully created.2) VG에 PV 합치기 — vgextend
#
$ sudo vgextend data_vg /dev/vdc
Volume group "data_vg" successfully extended.
$ sudo vgs data_vg
VG #PV #LV #SN Attr VSize VFree
data_vg 2 1 0 wz--n- 29.99g 19.99g ← 20G + 10GVG의 총 용량이 늘었습니다. 아직 LV는 그대로(10GB)입니다.
3) LV 확장 — lvextend
#
$ sudo lvextend -L +10G /dev/data_vg/data_lv
Size of logical volume data_vg/data_lv changed from 10.00 GiB to 20.00 GiB.
Logical volume data_vg/data_lv successfully resized.-L +10G는 “현재보다 10GB 더”, -L 20G는 “최종 20GB로” 입니다. + 차이를 헷갈리지 마세요. 전체로 가려면 -l +100%FREE.
4) 파일시스템 확장 — xfs_growfs
#
LV는 늘었지만, 그 위 파일시스템은 아직 옛 크기입니다. XFS 라면:
$ sudo xfs_growfs /data
$ df -hT /data
Filesystem Type Size Used Avail Use% Mounted on
/dev/mapper/data_vg-data_lv xfs 20G 175M 20G 1% /data ← 20G로 늘어남ext4라면 sudo resize2fs /dev/data_vg/data_lv. 마운트된 상태에서 확장 가능한 것이 핵심입니다. 다운타임 없이 디스크가 늘어납니다.
lvextend의 편의 옵션 —
-r(또는--resizefs)를 붙이면 LV 확장 + 파일시스템 확장을 한 번에 합니다.$ sudo lvextend -r -L +10G /dev/data_vg/data_lv운영에서는 거의 항상 이 쪽을 씁니다. 단, fs가 인식 가능한 종류여야 합니다(XFS, ext2/3/4, reiserfs 등).
축소 — XFS는 안 되고, ext4는 됨 #
기초 #6에서 짚은 함정. XFS는 축소 불가. ext4는 축소 가능합니다.
# 1. 마운트 해제 필수 (XFS와 다른 점 — ext4도 축소는 unmount 필요)
$ sudo umount /data
# 2. 파일시스템 검사
$ sudo e2fsck -f /dev/data_vg/data_lv
# 3. 파일시스템 축소
$ sudo resize2fs /dev/data_vg/data_lv 8G
# 4. LV 축소 (반드시 fs보다 같거나 큰 크기로)
$ sudo lvreduce -L 8G /dev/data_vg/data_lv
# 5. 다시 마운트
$ sudo mount /dev/data_vg/data_lv /data순서가 핵심 — fs 먼저 줄이고 LV 줄이기. 거꾸로 하면 데이터가 잘려나갑니다. 위험한 작업이라 운영에서는 백업 후에만 진행하고, 가능하면 새 LV 만들고 데이터 옮기는 쪽이 안전합니다.
스냅샷 — 한 시점을 통째로 잠그기 #
LVM의 가장 강력한 기능. 어떤 LV의 한 시점을 거의 즉시 떠두고, 그 이후의 변경은 별도로 관리해서 원본을 그대로 유지합니다.
원본 LV (data_lv) ─── 시간 →
│
├── 스냅샷 시점 (T0) — lvcreate -s
│
T0 │ T0이후 변경된 블록은 스냅샷에 별도 보관
│ 원본을 읽으면 현재, 스냅샷을 읽으면 T0 시점만들기 #
# data_lv의 T0 시점 스냅샷, 1GB의 변경량을 수용
$ sudo lvcreate -L 1G -s -n data_snap /dev/data_vg/data_lv
Logical volume "data_snap" created.
$ sudo lvs
LV VG Attr LSize Origin Data%
data_lv data_vg owi-aos--- 20.00g
data_snap data_vg swi-a-s--- 1.00g data_lv 0.01-s가 스냅샷 플래그. -L 1G는 변경량 (COW) 영역의 크기 — 원본 전체 크기가 아니라, T0이후 원본에서 변경되는 데이터를 수용할 공간입니다. 변경이 많을 것으로 예상되면 크게 잡습니다.
백업 패턴 #
스냅샷이 가장 자주 쓰이는 경우입니다.
# 1. 스냅샷 (즉시, 원본 멈추지 않음)
$ sudo lvcreate -L 5G -s -n data_snap /dev/data_vg/data_lv
# 2. 스냅샷을 마운트해 백업
$ sudo mkdir -p /mnt/snap
$ sudo mount -o ro,nouuid /dev/data_vg/data_snap /mnt/snap
$ sudo tar czf /backup/data-$(date +%F).tar.gz -C /mnt/snap .
# 3. 마운트 해제하고 스냅샷 제거
$ sudo umount /mnt/snap
$ sudo lvremove /dev/data_vg/data_snap원본은 백업 동안 한 번도 멈추지 않았고, 백업은 T0 시점의 일관된 데이터입니다. 원본을 stop 하지 않고 일관된 백업 — 운영의 표준 패턴입니다.
-o nouuid— XFS는 같은 UUID의 fs를 두 번 마운트하지 못하게 막아둡니다. 스냅샷은 원본과 같은 UUID를 갖기 때문에 이 옵션이 필요합니다. ext4는 필요 없습니다.
복구 (롤백) #
T0 시점으로 원본을 되돌리고 싶다면:
# 1. 원본 LV가 마운트돼 있으면 해제
$ sudo umount /data
# 2. 스냅샷을 원본에 병합
$ sudo lvconvert --merge /dev/data_vg/data_snap
Merging of volume data_vg/data_snap started.
Merge of snapshot into logical volume data_vg/data_lv has finished.
# 3. 다시 마운트하면 T0 상태
$ sudo mount /dev/data_vg/data_lv /data--merge가 스냅샷을 원본에 흡수시켜 T0으로 되돌립니다. 머지 후 스냅샷은 자동으로 사라져요.
활성 LV의 머지 — 원본이 쓰이는 중이라 unmount가 안 되면, 머지는 다음 활성화 시 (다음 부팅)에 일어납니다. 즉 재부팅하면 자동 롤백. 운영에선 이걸 의식하고 작업해야 합니다.
스냅샷의 한계 #
- 변경량 영역이 차면 스냅샷이 무효화 됩니다.
-L을 너무 작게 잡으면 백업 중에 망가질 수 있습니다. 보통 원본의 10~20% 가 안전선. - 장기 보관용이 아님. 스냅샷은 백업 / 임시 테스트 / 롤백에 쓰고, 영구 보관에는 별도 백업 (
tar,rsync, AWS S3 등)으로 옮겨야 합니다.
한 단계 더 — Thin Provisioning #
전통적 LV는 만들 때 정한 크기를 VG에서 즉시 잘라갑니다. 100GB LV 두 개를 만들면 VG에서 200GB가 즉시 차감됩니다. 실제 사용 데이터가 적어도요.
Thin LV는 “필요할 때만 가져가는” 방식입니다. VG에 100GB만 있어도 thin pool 위에서 200GB 짜리 thin LV 두 개를 만들 수 있습니다. (실제 사용량이 풀 용량을 넘지만 않으면.)
# 100GB의 thin pool
$ sudo lvcreate -L 100G -T data_vg/thin_pool
# pool 위에 200GB thin LV 두 개 (overprovisioning)
$ sudo lvcreate -V 200G -T data_vg/thin_pool -n thin_a
$ sudo lvcreate -V 200G -T data_vg/thin_pool -n thin_b
$ sudo lvs
LV VG Attr LSize Pool Data%
thin_pool data_vg twi-aotz-- 100.00g
thin_a data_vg Vwi-a-tz-- 200.00g thin_pool 0.01
thin_b data_vg Vwi-a-tz-- 200.00g thin_pool 0.01장점: 디스크 할당 유연성 + 즉시 만들기 + 효율적 스냅샷 (변경량 따로 잡지 않아도 됨).
단점: pool이 가득 차면 모든 thin LV가 멈춥니다. 모니터링 (lvs, 알람)이 필수.
운영에서는 컨테이너 워크로드 / 가상 머신 디스크처럼 동적으로 늘어나는 경우에서 자주 씁니다. 자세한 디자인은 고급 시리즈의 몫입니다.
다른 옵션 — Striping과 RAID #
Striping (RAID 0) #
여러 PV에 데이터를 나눠 써서 IO를 분산. 속도는 빠르지만 한 PV가 죽으면 전체 데이터 손실.
$ sudo lvcreate -L 10G -i 2 -I 64 -n stripe_lv data_vg
# -i 2: 2 개 PV에 stripe
# -I 64: 64KB 청크Mirroring (RAID 1) #
두 PV에 같은 데이터를 동기 복제. 한 PV가 죽어도 데이터 안전.
$ sudo lvcreate -L 10G -m 1 -n mirror_lv data_vg
# -m 1: 1 개의 추가 복사본RAID5 / RAID6 #
$ sudo lvcreate -L 10G --type raid5 -i 3 -n raid5_lv data_vg
# -i 3: 데이터 PV 3 개 + 자동으로 패리티 1 개 = 4 개 PV 필요운영에서는 하드웨어 RAID 또는 mdadm을 더 자주 쓰지만, LVM RAID는 디스크 두 장만으로 간편한 미러를 구성할 때 유용합니다.
모니터링 / 점검 #
용량과 상태 #
$ sudo pvs # PV 목록
$ sudo vgs # VG 목록
$ sudo lvs # LV 목록
$ sudo lvs -a # 숨겨진 내부 LV 까지 (스냅샷, thin metadata 등)$ sudo pvdisplay /dev/vdb
$ sudo vgdisplay data_vg
$ sudo lvdisplay /dev/data_vg/data_lv자동 활성화 #
$ sudo vgchange -a y data_vg # 활성화
$ sudo vgchange -a n data_vg # 비활성화 (마운트 해제 후)부팅 시 자동 활성화는 /etc/lvm/lvm.conf의 auto_activation_volume_list에서 제어합니다. 일반 운영은 기본값으로 충분합니다.
자주 만나는 함정 #
“lvextend 했는데 df가 그대로입니다”
#
LV만 늘리고 파일시스템 확장(xfs_growfs / resize2fs)을 안 한 경우입니다. -r 옵션으로 한 번에 가는 게 안전합니다.
“스냅샷이 갑자기 사라졌습니다” #
스냅샷의 변경량 영역이 가득 차면 자동으로 invalidate됩니다. lvs의 Data%가 100%에 가까워지면 즉시 더 큰 스냅샷으로 옮기거나, 백업을 끝내고 제거해야 합니다.
“VG에 PV가 안 들어갑니다 — ‘already in volume group’” #
이미 다른 VG에 속해 있는 PV. pvs로 어디 속해 있는지 확인. 진짜 안 쓰는 거면 그 VG에서 vgreduce로 빼고 가져옵니다.
“디스크 통째로 PV로 만들었는데 부팅 후 인식 안 됩니다” #
/etc/fstab에 디바이스 이름(/dev/vdb)으로 등록한 경우입니다. 디바이스 이름은 부팅마다 바뀔 수 있습니다. VG/LV 이름(/dev/data_vg/data_lv) 또는 UUID로 등록하면 문제없습니다.
“thin pool이 가득 찼습니다 — 모든 thin LV가 read-only” #
thin provisioning의 가장 큰 위험입니다. pool 80% 알람을 반드시 모니터링하고, 가득 차기 전에 lvextend로 pool 자체를 늘려야 합니다.
AlmaLinux / Rocky 차이 #
이번 글의 모든 명령이 그대로 동작합니다. LVM은 커널과 lvm2 패키지 위에서 동작하고, 그 패키지는 RHEL의 것을 그대로 가져옵니다.
자주 쓰는 명령 한 표 #
| 명령 | 하는 일 |
|---|---|
pvcreate <device> | PV 생성 |
pvs / pvdisplay <pv> | PV 목록 / 상세 |
vgcreate <vg> <pv>... | VG 생성 |
vgs / vgdisplay <vg> | VG 목록 / 상세 |
vgextend <vg> <pv> | VG에 PV 추가 |
vgreduce <vg> <pv> | VG에서 PV 제거 |
lvcreate -L <size> -n <lv> <vg> | LV 생성 (절대 크기) |
lvcreate -l 100%FREE -n <lv> <vg> | VG의 남은 공간 전부로 LV 생성 |
lvcreate -L <size> -s -n <snap> <orig> | 스냅샷 생성 |
lvcreate -L <size> -T <vg>/<pool> | thin pool 생성 |
lvcreate -V <size> -T <vg>/<pool> -n <lv> | thin LV 생성 |
lvextend [-r] -L +<size> <lv> | LV 확장 (+ fs도 함께) |
lvreduce -L <size> <lv> | LV 축소 (위험) |
lvconvert --merge <snap> | 스냅샷을 원본에 머지 (롤백) |
lvremove <lv> | LV 삭제 |
vgchange -a y/n <vg> | VG 활성화 / 비활성화 |
xfs_growfs <mount> | XFS 확장 |
resize2fs <device> | ext4 확장 / 축소 |
lvs / lvs -a | LV 목록 (+ 내부 LV까지) |
정리 #
이번 글에서 정리한 흐름:
- LVM은 **PV (물리) → VG (풀) → LV (논리)**의 세 층으로 디스크 운영을 추상화합니다.
- 새 디스크 추가의 표준:
pvcreate→vgcreate/vgextend→lvcreate→mkfs.xfs→ mount. - LV 확장은
lvextend -r -L +<size>한 줄로 (LV + fs 동시), 마운트된 상태로 안전. - XFS 축소 불가, ext4는 축소 가능하지만 위험. 가능하면 새 LV로 옮기기.
- 스냅샷은
lvcreate -s로 즉시 생성, 백업 / 롤백의 표준 패턴. 변경량 영역 크기에 주의. - Thin provisioning으로 over-provisioning이 가능하지만, pool 가득 참 모니터링이 필수입니다.
- Striping / Mirroring / RAID는 LVM 자체가 지원하지만 운영에선 hw RAID / mdadm이 더 일반적.
다음 — 스토리지 심화 #
LVM은 여전히 RHEL의 표준이지만, RHEL 8부터는 그다음 세대로 Stratis도 들어왔습니다. 단일 머신을 넘어 네트워크로 디스크를 공유하는 NFS / Samba 역시 운영에서 자주 만나는 영역입니다.
#3 스토리지 심화 — Stratis, NFS, Samba에서는 Stratis가 LVM + XFS 위에서 어떤 관리 모델을 제공하는지, NFS 서버 / 클라이언트의 설정 흐름, 그리고 Windows 호환 Samba까지 살펴봅니다. 로컬 디스크를 넘어 네트워크 스토리지를 다루는 방법을 정리하는 글입니다.