LVM ใน Linux: physical volume, volume group และ logical volume ในทางปฏิบัติ
LVM (Logical Volume Manager) บน Linux คือชั้นที่อยู่ระหว่างดิสก์และระบบไฟล์ ดิสก์ถูกแปลงเป็น physical volume (PV) รวมเป็น volume group (VG) และตัด logical volume (LV) ขนาดใดก็ได้ออกจากกลุ่มนั้น ข้อได้เปรียบหลักคือขยายโวลุ่มได้ทันทีด้วย lvextend -r เพิ่มดิสก์เข้ากลุ่มได้โดยไม่หยุดบริการ และสร้างสแนปชอตก่อนการเปลี่ยนแปลงที่มีความเสี่ยง
LVM (Logical Volume Manager) คือตัวจัดการโวลุ่มตรรกะบน Linux ที่แยกระบบไฟล์ออกจากดิสก์ทางกายภาพ แทนที่จะผูก /var ไว้กับพาร์ติชัน /dev/sdb1 ตายตัว คุณนำดิสก์มารวมในพูลกลาง แล้วตัดโวลุ่มขนาดที่ต้องการออกจากพูลนั้น เมื่อพื้นที่ไม่พอ โวลุ่มขยายได้ด้วยคำสั่งเดียว โดยไม่ต้องรีบูตและไม่ต้องหยุดบริการ ด้านล่างจะอธิบายว่า LVM บน Linux ทำงานอย่างไร วิธีสร้างโวลุ่มตั้งแต่ต้น วิธีขยาย วิธีสร้างสแนปชอต และวิธีหลีกเลี่ยงข้อผิดพลาดที่พบบ่อย
ทำไมต้องใช้ LVM ในเมื่อมีพาร์ติชันธรรมดาอยู่แล้ว
พาร์ติชันธรรมดาคือช่วงต่อเนื่องของดิสก์เพียงลูกเดียว ขนาดถูกกำหนดตอนแบ่งพาร์ติชัน และจะขยายได้ก็ต่อเมื่อมีพื้นที่ว่างต่อจากมันทันที เมื่อดิสก์เต็ม ต้องซื้อดิสก์ใหม่ ย้ายข้อมูล และแก้ /etc/fstab ในขณะที่บริการต้องหยุดทำงานไปด้วย
LVM แก้ปัญหาสามอย่าง:
- ขนาดยืดหยุ่น. โวลุ่มตรรกะขยายได้ (และสำหรับ ext4 ลดได้) ได้ทุกเมื่อ
- รวมดิสก์. ดิสก์ทางกายภาพหลายลูกกลายเป็นพูลเดียว และโวลุ่มหนึ่งอาจอยู่บนสองดิสก์ได้พร้อมกัน
- สแนปชอต. ภาพถ่ายโวลุ่ม ณ ขณะหนึ่งก่อนการอัปเดต การย้ายฐานข้อมูล หรือการดำเนินการที่มีความเสี่ยง
ด้วยเหตุนี้ตัวติดตั้งของ Ubuntu Server, RHEL, Rocky และ AlmaLinux จึงเสนอ LVM เป็นค่าเริ่มต้น และบนเซิร์ฟเวอร์ที่เก็บข้อมูลแทบทุกเครื่องก็ใช้ LVM
สามระดับของ LVM: PV, VG และ LV
ตรรกะทั้งหมดของ LVM สรุปได้เป็นสามแนวคิด ตัวอย่างเปรียบเทียบที่เข้าใจง่าย: ดิสก์คือถุงแป้ง กลุ่มคือคลังกลาง และโวลุ่มตรรกะคือแป้งที่ตักออกจากคลังตามปริมาณที่ต้องการ
| ระดับ | คืออะไร | ตัวอย่างชื่อ | สร้างด้วยคำสั่ง |
|---|---|---|---|
| PV (Physical Volume) | ดิสก์หรือพาร์ติชันที่ถูกเตรียมสำหรับ LVM | /dev/sdb, /dev/sdc1 | pvcreate |
| VG (Volume Group) | พูลที่รวม PV หนึ่งตัวหรือมากกว่า | data_vg | vgcreate |
| LV (Logical Volume) | โวลุ่มที่ตัดออกจาก VG ใช้สร้างระบบไฟล์บนนั้น | /dev/data_vg/app | lvcreate |
ภายใน VG พื้นที่ถูกแบ่งเป็นเอกซ์เทนต์ (PE, physical extents) ซึ่งเป็นบล็อกขนาดคงที่ ค่าเริ่มต้นคือ 4 MiB โวลุ่มตรรกะเป็นเพียงชุดของเอกซ์เทนต์ที่ไม่จำเป็นต้องเรียงติดกัน และอาจอยู่บนดิสก์ต่างลูกกัน นี่คือเหตุผลที่ขยายโวลุ่มได้ง่าย LVM เพียงแค่เพิ่มเอกซ์เทนต์ว่างให้โวลุ่มจากที่ใดก็ได้
โวลุ่มตรรกะเข้าถึงได้ด้วยพาธสองแบบที่เทียบเท่ากัน: /dev/data_vg/app และ /dev/mapper/data_vg-app เบื้องหลังเป็นอุปกรณ์ device-mapper ของเคอร์เนล
ตรวจสอบสิ่งที่มีอยู่
ตรวจก่อนว่าติดตั้งแพ็กเกจแล้ว: บน Debian และ Ubuntu คือ lvm2 (sudo apt install lvm2) ส่วนในตระกูล RHEL ติดตั้งมาพร้อมระบบ มีคำสั่งแบบสั้นและแบบละเอียดสำหรับดูภาพรวม:
$ sudo pvs
PV VG Fmt Attr PSize PFree
/dev/sdb data_vg lvm2 a-- <20.00g 0
/dev/sdc data_vg lvm2 a-- <20.00g <10.00g
$ sudo vgs
VG #PV #LV #SN Attr VSize VFree
data_vg 2 1 0 wz--n- 39.99g <10.00g
$ sudo lvs
LV VG Attr LSize Pool Origin Data% Meta%
app data_vg -wi-ao---- 30.00g
รายละเอียดเพิ่มเติมแสดงด้วย pvdisplay, vgdisplay และ lvdisplay ภาพรวมพร้อมพาร์ติชันธรรมดาดูได้ด้วย lsblk โวลุ่มตรรกะจะปรากฏเป็นชนิด lvm
$ lsblk /dev/sdb /dev/sdc
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sdb 8:16 0 20G 0 disk
└─data_vg-app 253:0 0 30G 0 lvm /srv/app
sdc 8:32 0 20G 0 disk
└─data_vg-app 253:0 0 30G 0 lvm /srv/app
ที่นี่โวลุ่ม app ขนาด 30 GB วางอยู่บนดิสก์สองลูกขนาด 20 GB ทั้งคู่ ซึ่งทำไม่ได้กับพาร์ติชันธรรมดา
LVM ตั้งแต่ต้น: จากดิสก์เปล่าถึงโวลุ่มที่เมานต์แล้ว
สมมติว่าเพิ่มดิสก์เปล่า /dev/sdb เข้าเซิร์ฟเวอร์ และต้องการโวลุ่มขนาด 15 GB สำหรับข้อมูลของแอปพลิเคชัน ตรวจชื่อดิสก์ด้วย lsblk สองครั้ง เพราะทุกคำสั่งด้านล่างจะลบข้อมูลบนอุปกรณ์ที่ระบุ
ขั้นที่ 1. สร้างฟิสิคัลโวลุ่ม
$ sudo pvcreate /dev/sdb
Physical volume "/dev/sdb" successfully created.
สามารถมอบดิสก์ทั้งลูกให้ LVM ได้ หรือสร้างพาร์ติชันก่อนด้วย fdisk หรือ parted โดยตั้งประเภทเป็น "Linux LVM" แล้วระบุพาร์ติชันนั้น (/dev/sdb1) พาร์ติชันทำให้ผู้ดูแลคนอื่นเข้าใจได้ชัดเจนขึ้น และป้องกันการแบ่งพาร์ติชันทับ LVM โดยไม่ตั้งใจ ส่วนการขยายดิสก์ทั้งลูกในคลาวด์ทำได้ง่ายกว่า
ขั้นที่ 2. สร้างกลุ่มโวลุ่ม
$ sudo vgcreate data_vg /dev/sdb
Volume group "data_vg" successfully created
ขั้นที่ 3. ตัดโวลุ่มตรรกะ
$ sudo lvcreate -n app -L 15G data_vg
Logical volume "app" created.
แฟล็ก -L กำหนดขนาดแบบสัมบูรณ์ ส่วน -l กำหนดเป็นจำนวนเอกซ์เทนต์หรือเปอร์เซ็นต์: -l 100%FREE ใช้พื้นที่ว่างทั้งหมดของกลุ่ม และ -l 50%VG ใช้ครึ่งหนึ่งของกลุ่ม การเก็บพื้นที่ว่างไว้ใน VG เป็นแนวปฏิบัติที่ดี เพราะสามารถมอบให้โวลุ่มใดก็ได้ภายหลัง หรือใช้เป็นพื้นที่ของสแนปชอต
ขั้นที่ 4. ระบบไฟล์และการเมานต์
$ sudo mkfs.ext4 /dev/data_vg/app
$ sudo mkdir -p /srv/app
$ sudo mount /dev/data_vg/app /srv/app
$ df -h /srv/app
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/data_vg-app 15G 24K 14G 1% /srv/app
หากต้องการให้โวลุ่มเมานต์หลังรีบูต เพิ่มบรรทัดลงใน /etc/fstab สำหรับโวลุ่มตรรกะพาธ /dev/mapper/... คงที่ จึงใช้พาธนั้นได้ หรือจะใช้ UUID จาก blkid ก็ได้:
/dev/mapper/data_vg-app /srv/app ext4 defaults 0 2
ตรวจรายการด้วย sudo mount -a ก่อนรีบูต เพราะข้อผิดพลาดใน fstab อาจทำให้เซิร์ฟเวอร์เข้าสู่โหมดฉุกเฉิน
ขยาย LVM โวลุ่มโดยไม่หยุดบริการ
นี่คือเหตุผลหลักที่ควรใช้ LVM โวลุ่มขยายได้ขณะที่ระบบไฟล์เมานต์อยู่ และแอปพลิเคชันยังเขียนข้อมูลต่อได้ วิธีการขึ้นอยู่กับว่ากลุ่มยังมีพื้นที่ว่างหรือไม่
หากใน VG ยังมีพื้นที่ว่าง
$ sudo vgs data_vg
VG #PV #LV #SN Attr VSize VFree
data_vg 1 1 0 wz--n- <20.00g <5.00g
$ sudo lvextend -r -L +4G /dev/data_vg/app
Size of logical volume data_vg/app changed from 15.00 GiB to 19.00 GiB.
Logical volume data_vg/app successfully resized.
resize2fs 1.47.0
Filesystem at /dev/mapper/data_vg-app is mounted on /srv/app; on-line resizing required
แฟล็กสำคัญคือ -r (--resizefs) ซึ่งขยายระบบไฟล์ทันทีหลังขยายโวลุ่ม หากไม่ใส่ โวลุ่มจะใหญ่ขึ้น แต่ df -h ยังแสดงขนาดเดิม เพราะระบบไฟล์ไม่รู้ว่ามีพื้นที่เพิ่ม นี่คือข้อผิดพลาดที่พบบ่อยที่สุด หากเกิดขึ้น ให้รัน resize2fs สำหรับ ext4 หรือ xfs_growfs สำหรับ XFS ด้วยตนเอง
$ sudo resize2fs /dev/data_vg/app # ext4 ระบุอุปกรณ์
$ sudo xfs_growfs /srv/app # XFS ระบุจุดเมานต์
ข้อสังเกต: -L +4G เพิ่มขึ้น 4 GB ส่วน -L 4G ตั้งขนาดรวมเป็น 4 GB หากต้องการให้โวลุ่มใช้พื้นที่ที่เหลือทั้งหมด ใช้ -l +100%FREE
หากพื้นที่ใน VG หมดแล้ว: เพิ่มดิสก์
เชื่อมต่อดิสก์ใหม่ (ในคลาวด์คือแนบโวลุ่มเพิ่ม) ค้นหาด้วย lsblk แล้วเพิ่มเข้ากลุ่ม:
$ sudo pvcreate /dev/sdc
$ sudo vgextend data_vg /dev/sdc
Volume group "data_vg" successfully extended
$ sudo lvextend -r -l +100%FREE /dev/data_vg/app
สามคำสั่ง ไม่มีเวลาหยุดทำงาน ระบบไฟล์อยู่บนดิสก์สองลูกแล้ว และแอปพลิเคชันไม่รู้สึกถึงการเปลี่ยนแปลงนี้
หากขยายดิสก์ในคลาวด์
ในคลาวด์มักง่ายกว่าที่จะไม่เพิ่มดิสก์ แต่ขยายดิสก์ที่มีอยู่แล้ว เมื่อนั้นเคอร์เนลจะเห็นขนาดใหม่ของอุปกรณ์ และต้องขยายฟิสิคัลโวลุ่มด้วย pvresize:
$ sudo pvresize /dev/sdb
Physical volume "/dev/sdb" changed
$ sudo lvextend -r -l +100%FREE /dev/data_vg/app
หาก PV สร้างบนพาร์ติชัน (/dev/sdb1) ให้ขยายพาร์ติชันก่อน เช่น ด้วย growpart /dev/sdb 1 จากแพ็กเกจ cloud-guest-utils แล้วจึงรัน pvresize /dev/sdb1
ลด LVM โวลุ่มได้หรือไม่
ทำได้ แต่ไม่ใช่กับระบบไฟล์ทุกชนิด และไม่สามารถทำขณะที่ระบบทำงานได้ XFS ลดขนาดไม่ได้เลย ต้องสร้างใหม่และย้ายข้อมูล ส่วน ext4 ลดได้ แต่ต้องเลิกเมานต์ก่อน:
$ sudo umount /srv/app
$ sudo lvreduce -r -L 10G /dev/data_vg/app
เมื่อใช้แฟล็ก -r LVM จะตรวจระบบไฟล์ (e2fsck) และย่อระบบไฟล์ก่อนลดโวลุ่ม หากไม่ใส่ -r คุณอาจตัดโวลุ่มให้เล็กกว่าระบบไฟล์ และทำให้ข้อมูลเสียหาย ก่อนลดขนาดต้องสำรองข้อมูลเสมอ
สแนปชอต LVM: ภาพถ่ายโวลุ่มก่อนการเปลี่ยนแปลงที่มีความเสี่ยง
สแนปชอตคือภาพถ่ายของโวลุ่มตรรกะ ณ ขณะหนึ่ง สร้างเสร็จในเวลาเพียงเสี้ยววินาทีและไม่คัดลอกข้อมูลทั้งหมด LVM ทำงานด้วยหลัก copy-on-write คือเก็บลงสแนปชอตเฉพาะบล็อกที่เปลี่ยนบนโวลุ่มต้นฉบับหลังจากสร้างสแนปชอต ดังนั้นสแนปชอตต้องการพื้นที่ใน VG เพียงเท่าจำนวนการเปลี่ยนแปลง ไม่ใช่ขนาดเต็มของโวลุ่ม
$ sudo lvcreate -s -n app_before_upgrade -L 2G /dev/data_vg/app
Logical volume "app_before_upgrade" created.
$ sudo lvs data_vg
LV VG Attr LSize Origin Data%
app data_vg owi-aos--- 19.00g
app_before_upgrade data_vg swi-a-s--- 2.00g app 0.01
คอลัมน์ Data% แสดงว่าพื้นที่เก็บการเปลี่ยนแปลงของสแนปชอตเต็มไปแล้วเท่าไร หากเต็ม 100% สแนปชอตแบบคลาสสิกจะใช้ไม่ได้ และทำได้เพียงลบทิ้ง เลือกขนาดให้เผื่อปริมาณการเปลี่ยนแปลงที่คาดไว้ และติดตามสแนปชอตที่มีอายุนานด้วย lvs หรือขยายด้วย lvextend
วิธีย้อนกลับไปยังสแนปชอต
หากการอัปเดตผิดพลาด ให้คืนโวลุ่มสู่สถานะตอนที่สร้างสแนปชอต:
$ sudo umount /srv/app
$ sudo lvconvert --merge /dev/data_vg/app_before_upgrade
Merging of volume data_vg/app_before_upgrade started.
$ sudo mount /srv/app
หลังการรวม (merge) สแนปชอตจะหายไป หากเลิกเมานต์โวลุ่มไม่ได้ (เช่น รูตของระบบ) การรวมจะรอจนกว่าโวลุ่มจะถูกเปิดใช้อีกครั้ง คือหลังรีบูต
หากทุกอย่างเรียบร้อยดี
ลบสแนปชอตทิ้งเพื่อไม่ให้ทำให้การเขียนช้าลงและไม่กินพื้นที่:
$ sudo lvremove /dev/data_vg/app_before_upgrade
สแนปชอตมีประโยชน์เมื่อเมานต์แบบอ่านอย่างเดียวเพื่อสำรองข้อมูลระบบที่กำลังทำงาน ด้วย mount -o ro และคัดลอกด้วย rsync หรือ tar สำหรับ XFS ให้เพิ่มตัวเลือก nouuid ไม่เช่นนั้นการเมานต์จะถูกปฏิเสธเพราะ UUID ซ้ำกับต้นฉบับ
LVM และ RAID: อย่าสับสนหน้าที่
LVM ไม่ได้ป้องกันความเสียหายของดิสก์ หากโวลุ่มกระจายอยู่บนดิสก์สองลูกและลูกหนึ่งเสีย โวลุ่มทั้งหมดจะเสียไป ไม่ใช่แค่ครึ่งหนึ่ง เพื่อความทนทานต่อความเสียหาย ให้วาง RAID (mdadm) ไว้ใต้ LVM หรือใช้โหมดมิเรอร์ที่มาพร้อมกับ LVM (lvcreate --type raid1 -m 1)
ทั้ง RAID และสแนปชอตไม่ได้มาแทนการสำรองข้อมูล สแนปชอตอยู่บนดิสก์เดียวกับต้นฉบับ ส่วน RAID จะทำมิเรอร์คำสั่ง rm -rf ที่พลาดไปด้วย จึงต้องมีสำเนาแยกไว้บนสื่ออื่น
ตารางคำสั่ง LVM
| งาน | คำสั่ง |
|---|---|
| ภาพรวม PV, VG, LV | pvs, vgs, lvs |
| สร้างฟิสิคัลโวลุ่ม | pvcreate /dev/sdb |
| สร้างกลุ่ม | vgcreate data_vg /dev/sdb |
| เพิ่มดิสก์เข้ากลุ่ม | vgextend data_vg /dev/sdc |
| สร้างโวลุ่ม | lvcreate -n app -L 15G data_vg |
| ขยายโวลุ่มและระบบไฟล์ | lvextend -r -L +5G /dev/data_vg/app |
| ขยาย PV หลังเพิ่มขนาดดิสก์ | pvresize /dev/sdb |
| สแนปชอต | lvcreate -s -n snap -L 2G /dev/data_vg/app |
| ย้อนกลับไปยังสแนปชอต | lvconvert --merge /dev/data_vg/snap |
| ถอดดิสก์ออกจากกลุ่ม | pvmove /dev/sdb แล้ว vgreduce data_vg /dev/sdb |
| ลบโวลุ่ม | lvremove /dev/data_vg/app |
ข้อผิดพลาดที่พบบ่อย
- ขยายโวลุ่มแล้ว แต่ df ยังแสดงขนาดเดิม. ลืมใส่
-rให้รันresize2fsหรือxfs_growfs - Insufficient free space. ไม่มีเอกซ์เทนต์ว่างในกลุ่ม ตรวจด้วย
vgsแล้วเพิ่มดิสก์ด้วยvgextendหรือขยาย PV - Device /dev/sdc excluded by a filter. ดิสก์ยังมีการแบ่งพาร์ติชันหรือลายเซ็นระบบไฟล์เก่าอยู่ หากแน่ใจว่าไม่ต้องการข้อมูลบนนั้น ล้างด้วย
wipefs -a /dev/sdc - สแนปชอตกลายเป็น Invalid. พื้นที่เก็บการเปลี่ยนแปลงเต็ม 100% กู้คืนไม่ได้ ทำได้เพียงลบทิ้ง และครั้งหน้าควรจัดสรรพื้นที่ให้มากขึ้น
สรุป
LVM บน Linux มีสามชั้น: ฟิสิคัลโวลุ่ม (PV) รวมเป็นกลุ่ม (VG) และตัดออกเป็นโวลุ่มตรรกะ (LV) ซึ่งให้สิ่งที่พาร์ติชันธรรมดาไม่มี ได้แก่ การขยายโวลุ่มขณะทำงานด้วย lvextend -r การเพิ่มดิสก์โดยไม่หยุดบริการ และสแนปชอตก่อนการเปลี่ยนแปลงที่มีความเสี่ยง จำไว้ว่า LVM ไม่ได้มาแทน RAID หรือการสำรองข้อมูล การแบ่งดิสก์ LVM RAID และโควตาถูกฝึกใช้จริงในบทเรียนหลักสูตร Linux
คำถามที่พบบ่อย
จะย้ายพาร์ติชันที่มีข้อมูลและทำงานอยู่ไปเป็น LVM ได้หรือไม่?
ทำโดยตรงไม่ได้ เพราะ pvcreate จะเขียนทับส่วนต้นของอุปกรณ์ ต้องสร้าง LVM บนดิสก์อีกลูก คัดลอกข้อมูลด้วย rsync แก้ fstab แล้วจึงค่อยคืนพาร์ติชันเก่า
LVM ทำให้ดิสก์ช้าลงหรือไม่?
หากไม่มีสแนปชอต ค่าใช้จ่ายของ device-mapper แทบไม่รู้สึก แต่สแนปชอตแบบคลาสสิกที่ทำงานอยู่จะทำให้การเขียนลงโวลุ่มต้นฉบับช้าลงเพราะ copy-on-write จึงไม่ควรเก็บไว้เป็นสัปดาห์
บนคอมพิวเตอร์ที่บ้านหรือแล็ปท็อปจำเป็นต้องใช้ LVM หรือไม่?
ไม่จำเป็น แต่มีประโยชน์เมื่อเข้ารหัสดิสก์ (LUKS โดยมี LVM อยู่ข้างใน) หรือเมื่อต้องการเปลี่ยนขนาดพาร์ติชันโดยไม่ต้องแบ่งใหม่ บนเซิร์ฟเวอร์ที่เก็บข้อมูล LVM เป็นมาตรฐานแทบทั้งหมด
thin provisioning ใน LVM คืออะไร?
คือโวลุ่มบาง สร้างพูลด้วย lvcreate --type thin-pool และโวลุ่มในพูลนั้นจะใช้พื้นที่จริงเท่าที่เขียนข้อมูลไปแล้ว จึงจัดสรรโวลุ่มได้มากกว่าพื้นที่ทางกายภาพที่มี แต่ต้องคอยดูว่าพูลเต็มหรือยัง
จะถอดดิสก์ออกจากกลุ่มโวลุ่มโดยไม่สูญเสียข้อมูลได้อย่างไร?
ย้ายเอกซ์เทนต์ออกไปยังดิสก์อื่นในกลุ่มด้วย pvmove /dev/sdb (ต้องมีพื้นที่ว่างพอ) แล้วรัน vgreduce data_vg /dev/sdb และ pvremove /dev/sdb
หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Linux: с нуля до уверенного администрирования”
ไปที่คอร์ส