前言

最近想装个 OpenStack 的块存储服务 Cinder ,结果一看官方文档,一来就是一块新硬盘。然而我们并没有这么富裕,而且 HDD 上还有大把空间没用呢。于是自己就试着弄弄,看看能不能新建一个卷组 cinder-volumesCinder 用。

之前最不敢弄的就是磁盘,毕竟里面全是电子数据,弄不好就得从头开始了。所以这次的作死记,也算是让自己好好学习了一波 Linux LVM 的知识,遂记之。

Linux LVM

其实只要一张图就能够解释清楚 Linux LVM 了:

Linux LVM 的层级非常清晰,在 LVM 中,一共有四个抽象性的概念,分别是:

  • 物理区域 Physical Extent PE :硬盘可供指派给逻辑卷的最小单位(通常为4MB)。可以认为物理区域是能够分配给任何分区的硬盘部分。
  • 物理卷 Physical Volume PV :可以在其上建立卷组 VG 的媒介(可以是硬盘分区,硬盘本身或是回环文件)。它包含一个特殊的 Header ,其余部分被分割为一块块的物理区域 PE。可以将物理卷认为是组成硬盘(阵列)的大型构建块。
  • 卷组 Volume Group VG :将一组物理卷作为一整个存储卷。其中能够包含逻辑卷。可以认为卷组是硬盘。
  • 逻辑卷 Logical Volume LV :由物理区域组成的“虚拟”分区。可以认为逻辑卷是普通的磁盘分区。

Linux LVM 的命令集:

不合理的分配

之前的分配方式是:

Logical VolumeSize
/dev/cl/root50 GB
/dev/cl/home920 GB
/dev/cl/swap4 GB

这台机子是 OpenStack 的计算节点,结果 / 目录的空间只有可怜的 50 GB, /home 目录却有 920 GB 之多。然而 nova 在新建空间分配系统盘时使用的是 / 下的空间,并不会使用 /home ,这就导致了 / 下几乎没有空间,然而 /home 下几乎没有使用的问题。

所以我决定要给 / 扩容至 400 GB,同时将 /home 缩小至 100 GB。

除此之外,由于 OpenStack 块存储服务 Cinder 的需要,还要重新分多一个分区,新建 cinder-volumes 卷组。

因此,新的分配方式应该是:

Logical VolumeSize
/dev/cl/root400 GB
/dev/cl/home100 GB
/dev/cl/swap4 GB
/dev/cinder-volumes/*300 GB

重新分配磁盘空间

清楚了 LVM 的基本层级之后,就好办多了。首先我们的希望是在原有卷组中减小 /home 的空间并增大 / 的空间,并且还要多预留空间提供给新的卷组。因此,先要在逻辑卷 LV 不是奢侈品包的那个 LV…… 层中做更改,使用的命令以 lv 开头。

请做好备份工作!这些操作会引起数据丢失

查看目录情况:

1
# df -h

删除 /home

备份 /home 目录:

1
# tar cvf /tmp/home.tar /home

必须备份!后面需要删除 /home 逻辑分区。

卸载 /home 目录:

1
# umount /home

若无法卸载,使用 fuser -m home 查看占用情况。

删除 /home 逻辑卷:

1
# lvremove /dev/mapper/cl-home

由于 CentOS 7 默认文件系统为 XFS ,而 XFS 并不如 ext4 般灵活,它只能够扩展而不能缩减分区大小,因此只能将 /home 逻辑卷删除。

扩展 /

扩展 / 逻辑卷:

1
# lvextend -L 400G /dev/mapper/cl-root

扩展 / 文件系统:

1
# xfs_growfs /dev/mapper/cl-root

新建 /home

新建 /home 逻辑卷:

1
# lvcreate -L 100G -n home cl

home 是逻辑分区名,cl 是卷组名。

/dev/mapper/cl-home 中创建 XFS 文件系统:

1
mkfs.xfs /dev/mapper/cl-home

重新挂载 /home

1
# mount /dev/mapper/cl-home /home

查看文件系统情况:

1
# df -h

恢复数据:

1
# tar xvf /tmp/home.tar -C /

重新分配磁盘分区

查看物理卷情况:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# pvdisplay

  --- Physical volume ---
  PV Name               /dev/sdb2
  VG Name               cl
  PV Size               930.51 GiB / not usable 4.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              238210
  Free PE               109186
  Allocated PE          129024
  PV UUID               gKMllN-ImJ9-06uZ-8pNP-kdG0-G42p-2Hfkgq

缩减物理卷

缩减物理卷:

1
# pvresize --setphysicalvolumesize 600G /dev/sdb2

缩减失败: 错误信息:/dev/sdb2: cannot resize to 153599 extents as later ones are allocated. 错误原因:硬盘扇区内容不连续。 解决方案:通过 pvdisplay -v -m 查看后使用 pvmove 迁移物理区域,使其能够在一个连续区间内。

查看物理卷情况:

1
# pvdisplay -v -m

迁移物理区域

此小节适用于缩减物理卷失败的情况,将会提供一个例子,作为迁移参考。

查看物理卷信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@Compute /]# pvdisplay -v -m

    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  --- Physical volume ---
  PV Name               /dev/sdb2
  VG Name               cl
  PV Size               930.51 GiB / not usable 4.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              238210
  Free PE               109186
  Allocated PE          129024
  PV UUID               gKMllN-ImJ9-06uZ-8pNP-kdG0-G42p-2Hfkgq
   
  --- Physical Segments ---
  Physical extent 0 to 1023:
    Logical volume	/dev/cl/swap
    Logical extents	0 to 1023
  Physical extent 1024 to 90623:
    Logical volume	/dev/cl/root
    Logical extents	12800 to 102399
  Physical extent 90624 to 116223:
    Logical volume	/dev/cl/home
    Logical extents	0 to 25599
  Physical extent 116224 to 225409:
    FREE
  Physical extent 225410 to 238209:
    Logical volume	/dev/cl/root
    Logical extents	0 to 12799

通过这些信息可以看出,11624 - 225409 段是空余的存储空间。由于其不在头或尾,物理卷无法缩减大小。因此,我们应该将 225410 - 238209 段中的数据移动到 11624 - 129023 段中 我为了方便留多了两个段,所以命令里是 129025

225410 - 238209 段中的数据移动到 11624 - 129025 段中:

1
[root@Compute /]# pvmove --alloc anywhere /dev/sdb2:225410-238209 /dev/sdb2:116224-129025

HDD 可能耗时较长。

再尝试缩减物理卷大小:

1
2
3
4
5
6
[root@Compute /]# pvresize --setphysicalvolumesize 600G /dev/sdb2

/dev/sdb2: Requested size 600.00 GiB is less than real size 930.51 GiB. Proceed?  [y/n]: y
  WARNING: /dev/sdb2: Pretending size is 1258291200 not 1951424512 sectors.
  Physical volume "/dev/sdb2" changed
  1 physical volume(s) resized / 0 physical volume(s) not resized

查看物理卷情况:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@Compute /]# pvdisplay -v -m

    Wiping internal VG cache
    Wiping cache of LVM-capable devices
  --- Physical volume ---
  PV Name               /dev/sdb2
  VG Name               cl
  PV Size               <600.00 GiB / not usable 3.00 MiB
  Allocatable           yes 
  PE Size               4.00 MiB
  Total PE              153599
  Free PE               24575
  Allocated PE          129024
  PV UUID               gKMllN-ImJ9-06uZ-8pNP-kdG0-G42p-2Hfkgq
   
  --- Physical Segments ---
  Physical extent 0 to 1023:
    Logical volume	/dev/cl/swap
    Logical extents	0 to 1023
  Physical extent 1024 to 90623:
    Logical volume	/dev/cl/root
    Logical extents	12800 to 102399
  Physical extent 90624 to 116223:
    Logical volume	/dev/cl/home
    Logical extents	0 to 25599
  Physical extent 116224 to 129023:
    Logical volume	/dev/cl/root
    Logical extents	0 to 12799
  Physical extent 129024 to 153598:
    FREE

原处于 225410 - 238209 段中的数据已被移动到 11624 - 129023 段中,129024 - 153508 段为该物理卷的空闲区域。

Linux LVM 中物理区域 (Physical Extent, PE) 通常为 4 MB,因此 0 - 153598 段中共有 153599 个 PE,总大小为:153599 * 4 / 1024 = 600 GB。

重新分配分区

使用 fdisk 来分配物理分区:

1
# fdisk /dev/sdb

p 列出该磁盘所有物理分区:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Command (m for help): p

Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes, 1953525168 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 4096 bytes
I/O size (minimum/optimal): 4096 bytes / 4096 bytes
Disk label type: dos
Disk identifier: 0x0008a020

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *        2048     2099199     1048576   83  Linux
/dev/sdb2         2099200  1953523711   975712256   8e  Linux LVM

d 删除原有 LVM 分区:

1
2
3
4
Command (m for help): d

Partition number (1,2, default 2): 2
Partition 2 is deleted

该分区必须删除后重建。

n 重建原来删除的物理分区 sdb2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Command (m for help): n

Partition type:
   p   primary (1 primary, 0 extended, 3 free)
   e   extended
Select (default p): p
Partition number (2-4, default 2): 2
First sector (2099200-1953525167, default 2099200): 2099200
Last sector, +sectors or +size{K,M,G} (2099200-1953525167, default 1953525167): +600G
Partition 2 of type Linux and of size 600 GiB is set

该分区的起始扇区 First sector 要与之前的之前被删除分区的起始扇区一致 (2099200)。

t 设置 sdb2 分区为 Linux LVM 分区:

1
2
3
4
5
Command (m for help): t

Partition number (1,2, default 2): 2
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'

n 新建一个新分区 sdb3

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Command (m for help): n

Partition type:
   p   primary (2 primary, 0 extended, 2 free)
   e   extended
Select (default p): p
Partition number (3,4, default 3): 3
First sector (1260390400-1953525167, default 1260390400): 
Using default value 1260390400
Last sector, +sectors or +size{K,M,G} (1260390400-1953525167, default 1953525167): +300G
Partition 3 of type Linux and of size 300 GiB is set

t 设置 sdb3 分区为 Linux LVM 分区:

1
2
3
4
5
Command (m for help): t

Partition number (1-3, default 3): 3
Hex code (type L to list all codes): 8e
Changed type of partition 'Linux' to 'Linux LVM'

w 保存分区设置并退出 fdisk

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
Command (m for help): w

The partition table has been altered!

Calling ioctl() to re-read partition table.

WARNING: Re-reading the partition table failed with error 16: Device or resource busy.
The kernel still uses the old table. The new table will be used at
the next reboot or after you run partprobe(8) or kpartx(8)
Syncing disks.

需要重启使用新分区生效。

查看分区情况:

1
# fdisk -l

创建卷组

分区完成后,我们还需建立 cinder-volumes 的卷组。

新建物理卷

列出可被用作物理卷的设备:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# lvmdiskscan

  /dev/cl/root [     400.00 GiB] 
  /dev/sda1    [     100.00 MiB] 
  /dev/cl/swap [       4.00 GiB] 
  /dev/sda2    [    <238.38 GiB] 
  /dev/cl/home [     100.00 GiB] 
  /dev/sdb1    [       1.00 GiB] 
  /dev/sdb2    [     600.00 GiB] LVM physical volume
  /dev/sdb3    [     300.00 GiB] LVM physical volume
  3 disks
  3 partitions
  0 LVM physical volume whole disks
  2 LVM physical volumes

选用 /dev/sdb3 创建新的物理卷:

1
2
3
# pvcreate /dev/sdb3

  Physical volume "/dev/sdb3" successfully created.

新建卷组

创建包含 /dev/sdb3 物理卷的 cinder-volumes 卷组:

1
2
3
# vgcreate cinder-volumes /dev/sdb3

  Volume group "cinder-volumes" successfully created

至此,终于达到了我们之前的目标,庆祝一下吧 :)

参考资料


知识共享许可协议
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。