LVM 以及 PVE 的存储结构

LVM 的基本组成部分、常用命令、精简卷的概念及操作,以及 PVE 系统中的存储管理和虚拟硬盘挂载方法。

LVM 是啥

逻辑卷管理器(Logical Volume Manager)是 Linux 内核提供的功能。可以在磁盘的上创建一层抽象层,使得对磁盘分区的管理变为对逻辑卷的管理。不仅可以方便分割系统,还能在不停止程序或者卸载文件系统的情况下调整大小和移动。

LVM 有几个基本的组成部分:

物理卷(PV,physical volume)对应着物理硬盘或者分区。需要把要使用的分区或者磁盘初始化之后,才可以被 LVM 管理。

卷组(VG,volume group)把多个物理卷(PV)汇集在一起,形成一个单一的逻辑存储池。在卷组中,可用于分配的磁盘空间被分成固定大小的单元,称之为物理扩展(PE,physical extent),这是可以被分配的最小空间单位。

逻辑卷(LV,logical volume)是可以从卷组(VG)中划分出来的虚拟块存储设备。逻辑卷可以方便地调整大小。可以创建不同类型的逻辑卷设备,其中最常用的是线性卷。

LVM 的组成元素 | Wikipedia

常用的 LVM 命令

查询:

1
2
3
4
5
6
7
8
9
10
lvm help # 查看所有 LVM 命令
man lvdisplay # 使用 man 查看命令的使用方法
pvs
pvdisplay
lvs
lvs -a # 显示所有的,包括非常规的卷信息,例如元数据、快照等
lvdisplay
lvdisplay -m /dev/myvg/mylv # 显示详细的卷信息,包括物理卷的使用情况
vgs
vgdisplay

初始化,创建一个 ext4 格式的线性逻辑卷:

1
2
3
4
5
6
7
8
9
10
11
# 将新的分区初始化为物理卷
pvcreate /dev/sdb1
# 创建一个名叫"myvg"的卷组,并加入逻辑卷
vgcreate myvg /dev/sdb1
# 创建一个 20GB 的逻辑卷,命名为"mylv"
lvcreate -L 20G -n mylv myvg
# 给逻辑卷格式化
mkfs.ext4 /dev/myvg/mylv
# 创建挂载点和挂载
mkdir -p /mnt/mydata
mount /dev/myvg/mylv /mnt/mydata

使用一个新硬盘分区给一个 ext4 逻辑卷扩容:

1
2
3
4
5
6
7
8
9
10
# 创建新物理卷
pvcreate /dev/sdc1
# 将新的物理卷添加到卷组
vgextend myvg /dev/sdc1
# 把"mylv"逻辑卷扩展 10GB
lvextend -L +10G /dev/myvg/mylv
# 扩展 ext4 文件系统,使其利用新的空间
resize2fs /dev/myvg/mylv
# 检查
df -h /mnt/mydata

移除一个物理卷:

1
2
3
4
5
6
7
8
# 检查要移除的 LV 使用了哪些 PV
lvdisplay -m /dev/myvg/mylv
# 将迁移数据迁移出指定 PV,如果空间不够会报错
pvmove /dev/sdc1
# 把物理卷移除卷组,如果 PV 上还有数据被使用会报错
vgreduce myvg /dev/sdc1
# 移除物理卷分区标识,如果 PV 还被使用会报错
pvremove /dev/sdc1

如果因为分区已经分配无法移除物理卷,还需要缩小分区大小。ext4 和一些其他的分区格式不支持在挂载状态下缩小大小,这时候就只能先卸载分区了。

Q&A

LVM 的卷组、逻辑分区的信息保存在哪里?

在被标识为物理卷的 LVM 分区,在分区开头的扇区都会有分区标识自己是 LVM 分区;分区标识的后面是元数据区域,这里储存着整个卷组的所有元数据信息。每一个 LVM 分区的元数据区域都储存了一样的元数据,是冗余的。元数据区域后面才是可用的存储空间。

在文件系统中也会保存 LVM 元数据的信息。/etc/lvm/backup 目录包含当前的 VG 配置,而/etc/lvm/archive 目录则包含 VG 配置的历史版本。可以使用 vgcfgbackup 来手动备份卷组元数据信息。

LVM 的逻辑分区支持哪些分区格式?

LVM 理论上支持所有的分区格式,因为 LVM 本身不涉及文件系统格式,只是提供了逻辑卷的管理和分配。我觉得逻辑卷可以认为是一个能提供储存能力的虚拟硬盘设备。

只有 Linux 系统能使用 LVM 吗?

是的。LVM 是为 Linux 设计的。在别的类型的操作系统可能需要额外的软件来读取 LVM 分区。其他的操作系统也有类似逻辑卷的功能,例如 Windows 的 Storage Spaces

开机的时候,启动引导怎么知道 LVM 分区的操作系统?

GRUB 是支持 LVM 的,可以正确识别和引导 LVM 分区的系统。

假如我的一个 LV 的数据正好映射到了两块硬盘上的不同分区,然后其中一块硬盘坏了,会发生什么?

在虚拟机上面试了一下,会无法识别分区,整个卷组处于未激活状态:

1
2
3
4
5
6
7
8
9
10
$ sudo lvscan
WARNING: Couldn't find device with uuid Yagcex-Xx5x-GCaJ-btvS-yG3D-IHZv-dhdpsj.
WARNING: Couldn't find device with uuid NXyYXX-ebvq-GMIz-fbqy-b311-5CM2-gOxa3M.
WARNING: VG myvg is missing PV Yagcex-Xx5x-GCaJ-btvS-yG3D-IHZv-dhdpsj (last written to /dev/sda1).
WARNING: VG myvg is missing PV NXyYXX-ebvq-GMIz-fbqy-b311-5CM2-gOxa3M (last written to /dev/sda2).
inactive '/dev/myvg/mylv' [2.50 GiB] inherit

$ sudo mount /dev/myvg/mylv /mnt
mount: /mnt: wrong fs type, bad option, bad superblock on /dev/mapper/myvg-mylv, missing codepage or helper program, or other error.
dmesg(1) may have more information after failed mount system call.

如果真的发生了这种情况,有教程通过拿新的硬盘分区替换丢失的 PV,然后重新挂载,可以恢复部分正好不储存在丢失 PV 的数据,不过恢复的结果还需要看硬盘的损坏程度和文件存储的实际位置。数据损坏程度也和逻辑卷的类型有关系,如果 LV 类型是镜像卷或者 RAID 卷,可能可以完全恢复数据,而线性卷就比较困难;条带卷因为数据被分割和分开存储,一旦其中一个 PV 损坏,恢复数据几乎不可能了。

PVE 的储存结构

PVE(Proxmox Virtual Environment)是一款开源的虚拟化管理平台,可以管理 KVM 和 LXC 容器虚拟化。PVE 支持多种存储类型,包括目录、LVM、ZFS、NFS、CIFS 等,这里主要关注了一下默认安装的虚拟机储存方式,也就是使用 LVM 的情况下的储存结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@pve:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
nvme0n1 259:0 0 476.9G 0 disk
├─nvme0n1p1 259:1 0 1007K 0 part
├─nvme0n1p2 259:2 0 1G 0 part /boot/efi
├─nvme0n1p3 259:3 0 128G 0 part
│ ├─pve-swap 253:0 0 16G 0 lvm [SWAP]
│ ├─pve-root 253:1 0 30G 0 lvm /
│ ├─pve-data_tmeta 253:2 0 1G 0 lvm
│ │ └─pve-data-tpool 253:4 0 70G 0 lvm
│ │ ├─pve-data 253:5 0 70G 1 lvm
│ │ ├─pve-vm--100--disk--0 253:6 0 30G 0 lvm
│ │ ├─pve-vm--101--disk--0 253:7 0 30G 0 lvm
│ │ └─pve-vm--102--disk--0 253:8 0 2.1G 0 lvm
│ └─pve-data_tdata 253:3 0 70G 0 lvm
│ └─pve-data-tpool 253:4 0 70G 0 lvm
│ ├─pve-data 253:5 0 70G 1 lvm
│ ├─pve-vm--100--disk--0 253:6 0 30G 0 lvm
│ ├─pve-vm--101--disk--0 253:7 0 30G 0 lvm
│ └─pve-vm--102--disk--0 253:8 0 2.1G 0 lvm
└─nvme0n1p4 259:4 0 200G 0 part
1
2
3
4
5
6
7
8
9
root@pve:~# lvs
LV VG Attr LSize Pool Origin Data% Meta%
data pve twi-aotz-- 70.00g 69.65 3.19
root pve -wi-ao---- 30.00g
snap_vm-100-disk-0_231107 pve Vri---tz-k 20.00g data vm-100-disk-0
swap pve -wi-ao---- 16.00g
vm-100-disk-0 pve Vwi-aotz-- 30.00g data 97.93
vm-101-disk-0 pve Vwi-aotz-- 30.00g data 47.03
vm-102-disk-0 pve Vwi-aotz-- 2.12g data 8.37

可以看到,除了 efi 启动分区,整个 PVE 系统的储存都在 LVM 的管理下。卷组的名称是 pve,名为 root 的卷储存了根文件系统,swap 卷是交换分区。data 卷是一个 “精简池”(Thin Pool)逻辑卷,vm- 开头的逻辑卷都是从这个精简池创建出来的。

lsblk 命令的结果里,逻辑卷会被命名成卷组名-逻辑卷名。在这里还可以看到带 meta 字样的块设备,这些是精简池的元数据信息,lvs -a 也可以看到它们。

lvs 命令结果的 Attr 属性标识了逻辑卷的信息,第一位是逻辑卷的类型。- 是普通逻辑卷,t 是精简池,V 是精简卷。更详细的类型标识信息可以在 man lvs 看到。

vm 开头的几个是 PVE 虚拟机的虚拟硬盘。snap_vm-100-disk-0_231107 是编号为 100 的虚拟机的快照生成的原硬盘的快照卷。

精简卷

精简配置逻辑卷(thinly-provisioned logical volume)是一种特殊类型的逻辑卷,创建出来逻辑卷并不会马上分配,而是到使用的时候才分配。因此可以创建出比实际可用空间更大的逻辑卷,可以更加经济高效的分配存储空间。(当然,也是有代价的,你必须经常检查逻辑卷使用和分配的情况,关注数据的增长,给精简池扩容,一旦存满了虚拟机和系统就会开始报错……)

pve 节点的管理页面可以查看精简池的使用率

精简卷可以用 lvextend 命令扩容,但是不能缩小大小。

PVE 利用了精简卷的特性,实现了类似 ESXi 磁盘文件的“精简置备”功能,只有在真正使用的时候才分配磁盘空间。并且还利用了快照功能,使得创建虚拟机镜像也因为写时复制(Copy-on-Write)技术节省了空间。

挂载虚拟硬盘

需要安装 kpartx:

1
apt install kpartx

操作前将对应的虚拟机关机。

查看块设备信息列表:

1
2
3
4
5
6
7
8
root@pve:~# blkid
...
/dev/mapper/pve-root: UUID="f3021b2d-00be-4cd4-b8a5-398c7005336d" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mapper/pve-swap: UUID="d0992b64-c36f-4171-82fc-9fccc5b37ce4" TYPE="swap"
/dev/mapper/pve-vm--101--disk--0: UUID="115c5c12-45ed-46dd-97d7-6365ef987aeb" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mapper/pve-vm--102--disk--0: PTUUID="0bf605d0-65dd-058c-3548-b83d11220200" PTTYPE="gpt"
/dev/mapper/pve-vm--100--disk--0: PTUUID="223180e3" PTTYPE="dos"
...

找到对应磁盘后,可以查看磁盘分区:

1
2
3
root@pve:~# kpartx -l /dev/mapper/pve-vm--100--disk--0 
pve-vm--100--disk--0p1 : 0 1124352 /dev/mapper/pve-vm--100--disk--0 2048
pve-vm--100--disk--0p2 : 0 61788160 /dev/mapper/pve-vm--100--disk--0 1126400

添加分区映射:

1
2
3
root@pve:~# kpartx -av /dev/mapper/pve-vm--100--disk--0 
add map pve-vm--100--disk--0p1 (253:9): 0 1124352 linear 253:6 2048
add map pve-vm--100--disk--0p2 (253:10): 0 61788160 linear 253:6 1126400

添加完可以看到已经出现了对应设备:

1
2
3
4
5
6
root@pve:~# blkid -d
...
/dev/mapper/pve-vm--101--disk--0: UUID="115c5c12-45ed-46dd-97d7-6365ef987aeb" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mapper/pve-vm--100--disk--0p2: BLOCK_SIZE="512" UUID="EE58234B582311BF" TYPE="ntfs" PARTUUID="223180e3-02"
/dev/mapper/pve-vm--100--disk--0p1: LABEL="系统保留" BLOCK_SIZE="512" UUID="08662237662225C2" TYPE="ntfs" PARTUUID="223180e3-01"
...

这是一个 Windows 系统。选择挂载其中一个设备:

1
2
3
4
5
6
7
8
9
root@pve:~# mount /dev/mapper/pve-vm--100--disk--0p2 /mnt
root@pve:~# ls /mnt
'$Recycle.Bin' 'Program Files'
'Documents and Settings' 'Program Files (x86)'
https_console.sunlogin.oray.com.localstorage Recovery
https_sunlogin.oray.com.localstorage 'System Volume Information'
pagefile.sys Users
PerfLogs Windows
ProgramData 迅雷下载

现在就可以操作虚拟硬盘上的文件了。

取消挂载和映射:

1
2
3
4
root@pve:/# umount /mnt
root@pve:/# kpartx -dv /dev/mapper/pve-vm--100--disk--0
del devmap : pve-vm--100--disk--0p1
del devmap : pve-vm--100--disk--0p2

参见:

作者

Lazyb0x

发布于

2024-06-27

更新于

2024-07-14

许可协议

评论