搞Linux运维的人应该都有这种体验:CentOS 7安装器默认就会用LVM分区,装系统的时候一路下一步,等到服务器跑了两三年,根分区被日志和容器镜像撑满了才反应过来——当初如果不懂LVM,扩容只能靠重装系统,或者多插一块盘做软链接把数据搬出去;但只要你把LVM那套结构弄明白了,其实三条命令就能在线把新磁盘空间“搬”进根分区,数据不用动,服务不用停。这篇文章就围绕CentOS 7的LVM分区,把LVM的核心原理、安装时的分区规划、运维中最常用的扩容缩容操作,以及我这些年踩过的坑一并整理出来。不管你是刚入门的新手,还是早就用过但偶尔被xfs缩容坑一把的老手,应该都能从里面捞到点实在的东西。
1. 先弄明白LVM的三层结构
1.1 为什么传统分区不够用
传统分区方式,是把一块磁盘切成若干个独立分区,每个分区对应一个挂载点,分区大小在建立的时候就固定了。问题在于:切完之后想改大小非常麻烦,尤其是我刚工作那几年,经常遇到某个分区快满了、另一个分区却剩下几十G闲置的情况。想腾挪空间?只能备份数据、删分区、重新划分、再恢复数据,一套操作下来,半夜两点都在机房喝咖啡。
LVM(Logical Volume Manager)把磁盘空间从“固定分区”变成了“可拆组的积木”。它是在内核层面加了一层抽象,让文件系统不再直接面对物理磁盘分区,而是面对一个可以随时调整大小的逻辑卷。空间不够,就把新的磁盘或分区加进这个池子,然后把池子里的空间划给某个逻辑卷,整个过程可以在线完成,不需要卸载文件系统。这个特性对生产服务器来说太重要了,尤其是数据库、日志这类增长不可控的业务。
1.2 PV、VG、LV和PE,一张图讲清楚
LVM里有四个核心概念,我用大白话拆一遍:
- PV(Physical Volume,物理卷):把一块磁盘或一个磁盘分区初始化成PV,LVM才能管理和使用它。你可以对整块盘做PV,也可以对一个分区做PV。
- VG(Volume Group,卷组):一个或多个PV组合在一起,形成一个统一的存储池子。VG就是那个“大池子”,所有空间都汇总在这里。
- LV(Logical Volume,逻辑卷):从VG池子里划分出来的一个块,我们给它格式化、挂载,像使用普通分区一样使用它。
- PE(Physical Extent,物理扩展块):VG分配空间的最小单位,CentOS 7默认PE大小是4MiB。LV的每一次扩容或缩容,都是PE的整数倍。
用仓库来类比:PV是仓库的一堵堵墙,VG是整个仓库的使用面积,LV是在仓库里隔出来的一个房间。房间大小不需要跟墙皮完全对应,你可以随时拆掉一面墙扩大房间,也可以在房间中间加一道临时隔断缩小它。这就是LVM灵活性的来源。
1.3 CentOS 7默认的LVM布局长什么样
CentOS 7默认安装时如果选择了自动分区,安装器会帮我们创建如下结构:
/dev/sda1:通常是1G的/boot分区,采用普通分区方式,不是LVM。/dev/sda2:标记为“Linux LVM”类型,占掉磁盘剩余所有空间,成为LVM的PV。- 安装器会基于这个PV创建一个名为
centos的VG(在CentOS 8/9上VG名变成了cl)。 - 在这个VG里默认创建三个LV:
root、swap、home,挂载点分别是/、swap和/home。
用lsblk命令看下来,大致长这样:
[root@localhost ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 200G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 199G 0 part ├─centos-root 253:0 0 50G 0 lvm / ├─centos-swap 253:1 0 4G 0 lvm [SWAP] └─centos-home 253:2 0 145G 0 lvm /home很多刚接触LVM的人会在这里犯迷糊:为什么/不是直接挂在分区上,而是挂在centos-root上?因为/挂载点对应的实际上是一个逻辑卷,逻辑卷通过内核的设备映射器(device mapper)映射到物理磁盘上。这个设计决定了它可以在线调整大小。
1.4 为什么/boot不放进LVM
有人会问:既然LVM这么好,为什么/boot还要单独用普通分区?原因主要有两个:
- 引导器的兼容性:GRUB等引导程序在系统启动阶段需要读取
/boot目录下的内核和initramfs文件。虽然现代GRUB2理论上支持从LVM逻辑卷引导,但普通分区是最成熟、最不会出问题的方案。安装器这么做,是为了把启动失败的风险降到最低。 - 故障域隔离:LVM涉及多层映射,一旦VG元数据损坏或者LV激活失败,系统可能无法正常启动。
/boot独立出来,至少保证引导过程不依赖LVM,出了问题还能通过救援模式修。
所以我的建议是:除非你很清楚自己在干什么,否则永远不要动系统的/boot分区,也不要试图把它并进LVM。
1.5 什么时候该用LVM,什么时候不该用
LVM适合服务器场景,尤其是这几类:
- 日志服务、监控系统,磁盘空间增长不可预知;
- 数据库服务器,需要根据数据增长持续扩容;
- 虚拟机宿主机,经常要动态调整虚拟机磁盘大小。
LVM不太适合的场景:
- 个人电脑,日常使用空间需求变化小,LVM反而多一层复杂度;
- 单块小容量磁盘(比如32G的U盘),LVM的灵活优势体现不出来,还可能导致分区结构复杂;
- 对性能有极端要求的场景,LVM会有轻微的性能损耗,虽然现代硬件上基本感知不到。
选型原则很简单:生产环境有动态扩容需求,用LVM;没有这个需求,普通分区也够用,别为了“显得专业”去引入复杂性。
2. 安装CentOS 7时,LVM分区规划怎么做
2.1 安装器里的自定义分区步骤
安装CentOS 7时,在“安装信息摘要”页面进入“安装位置”,选择目标磁盘后,点击“自定义分区配置”。接下来的操作顺序是:
- 为新系统创建
/boot分区,设备类型选择“标准分区”,大小建议1G。 - 创建
/和/home挂载点时,设备类型选择“LVM”,大小为LVM设备分配初始空间。 - 创建swap时,设备类型同样选“LVM”。
- 安装器会提示“将自动创建LVM卷组”,默认VG名为
centos,点击“修改”可以设置VG名和PE大小。 - 如果磁盘空间有富余,也可以在点击“修改”的界面里勾选“创建空间不足时自动缩容”,让安装器自己把剩余空间全部塞进VG。
注意一个细节:安装界面里给/分配的大小,其实是分配给逻辑卷root的初始大小,而不是这个LV的硬上限。只要VG里还有剩余空间,以后想扩随时能扩。所以安装时不需要把空间一次性全给/,但也不建议把/分得太小,否则系统跑起来空间告急再扩,虽然技术上可行,但操作总是有风险。
2.2 一套比较稳的分区规划参考
以一个200G的系统盘为例,我的推荐方案是:
| 挂载点/用途 | 文件系统 | 大小 | 说明 |
|---|---|---|---|
| /boot | xfs | 1G | 普通分区,放内核和引导文件,不建议动 |
| / | xfs | 150G | LVM,系统根目录,日志、软件、数据都有余量 |
| /home | xfs | 0G或20G | LVM,如果机器是纯服务器,不建议单独分home |
| swap | swap | 4G~8G | LVM,按物理内存大小,一般给内存的1~2倍 |
这里有个很多新手会踩的坑:CentOS 7安装器默认创建/home,而且会瓜分掉磁盘一大半空间。如果这台机器是做服务器用,用户根本不会登录图形界面,/home常年空置,而/反而空间不足。所以我的习惯是,装服务器时干脆不创建/home,把所有可用空间都划给/,以后真需要单独挂载点,再用LVM动态创建。如果初始分区分错了,别急,后面第4章会有重新分配/home空间的完整操作。
2.3 解释一个设计:PE大小到底该怎么选
PE默认4MiB,对应VG最大空间上限大约是256GB(65534个PE乘以4MiB)。如果你规划的总容量超过256G,安装器或者vgcreate时就需要指定更大的PE。比如:
vgcreate -s 8M vg_data /dev/sdb1PE大小会影响一个逻辑卷的最大容量和空间分配粒度。PE越大,单个LV可以做大,但空间碎片的可能也越大;PE越小,空间利用率越高,但LV容量上限越低。在CentOS 7的实际运维中,如果不做超大规模存储,默认4M完全够用,我从来没去动过这个值。
3. 已有系统上的LVM管理实操
3.1 环境检查与工具确认
不管哪个场景,核心命令都来自lvm2这个软件包,CentOS 7默认是装好的。万一命令不存在,先装:
yum install -y lvm2 xfsprogs然后看一下当前的LVM状态:
pvs # 查看PV物理卷 vgs # 查看VG卷组 lvs # 查看LV逻辑卷 pvscan # 扫描并列出所有PV vgdisplay centos以我手上一台模拟环境为例,输出如下:
[root@localhost ~]# pvs PV VG Fmt Attr PSize PFree /dev/sda2 centos lvm2 a-- <199.00g 8.00g [root@localhost ~]# vgs VG #PV #LV #SN Attr VSize VFree centos 1 3 0 wz--n- <199.00g 8.00g [root@localhost ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert root centos -wi-ao---- 50.00g home centos -wi-ao---- 145.00g swap centos -wi-ao---- 4.00g从输出里可以清楚看到,目前VG里还剩8G可用空间没有分配。这就是后续扩容的“余粮”。
3.2 新增磁盘并创建PV的完整流程
现在假定虚拟化平台给这台机器新增了一块100G的磁盘,在系统里显示为/dev/sdb。第一步先分区。
[root@localhost ~]# fdisk /dev/sdbfdisk交互命令依次输入:
n # 新建分区 p # 选择主分区 1 # 分区号1 回车 # 起始扇区默认 回车 # 结束扇区默认,用满整块盘 t # 改变分区类型 8e # Linux LVM类型 p # 预览分区表 w # 写入并退出如果磁盘容量超过2T,推荐用parted做GPT分区,用fdisk的话需要手动选GPT模式。分区完成后执行partprobe /dev/sdb让内核重新读取分区表,再用lsblk确认新分区已经看到:
[root@localhost ~]# lsblk /dev/sdb sdb 8:16 0 100G 0 disk └─sdb1 8:17 0 100G 0 part其实也可以直接用整块盘做PV(pvcreate /dev/sdb),但我的习惯还是先分区。原因有几个:分区表里能看到明确的LVM标记,以后交接给别人时更容易看懂;某些管理工具对“裸盘PV”识别不友好;万一后续想移除其中一部分空间,有分区表更容易操作。
创建PV并纳入VG:
pvcreate /dev/sdb1 vgextend centos /dev/sdb1执行后vgs可以看到VG总容量从199G变成了299G,pvs也能看到新PV的归属和剩余空间。到这一步,池子已经变大了,但还没有给任何LV扩容,所以df -h暂时不会看到任何变化。
3.3 从VG里创建新逻辑卷并挂载
如果新增空间不是要给根分区,而是要给某个业务单独使用,就需要在VG里创建新LV。例如创建一个80G的LV:
lvcreate -L 80G -n lv_data vg_data注意-n指定LV名称,-L指定大小。创建完成后格式化和挂载:
mkfs.xfs /dev/vg_data/lv_data mkdir /data mount /dev/vg_data/lv_data /data这样/data就是一个全新的、可用的存储挂载点。如果后续想把这个LV扩到100G,只需要在线执行:
lvextend -L 100G /dev/vg_data/lv_data xfs_growfs /data全程不需要卸载,业务无感知。这就是LVM最吸引人的地方。
3.4 为什么很多教程建议用UUID写fstab
如果希望重启后依然自动挂载,需要写入/etc/fstab。最稳妥的方式是使用文件系统的UUID,而不是设备路径。通过blkid命令查看UUID:
[root@localhost ~]# blkid /dev/vg_data/lv_data /dev/vg_data/lv_data: UUID="12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="xfs"然后追加一行:
UUID="12345678-xxxx-xxxx-xxxx-xxxxxxxxxxxx" /data xfs defaults 0 0为什么不建议直接写/dev/mapper/vg_data-lv_data?因为设备路径在某些场景下(比如系统重启后磁盘顺序变化、VG元数据恢复)可能发生变更,而UUID是文件系统创建时生成的全球唯一标识,基本不可能冲突。不过一般来说控制器顺序不会乱,/dev/mapper/vg-lv路径也是可以接受的;如果是云环境,更推荐UUID,因为云盘挂载顺序真的会因为热插拔而变化。
改完fstab,建议先执行mount -a测试,再重启验证。别等重启之后发现挂载失败才排查,那样可能已经来不及登录进系统了。
4. 核心场景:动态扩容与缩容实战
4.1 场景一:用新增磁盘扩容根逻辑卷
这是生产环境最典型的场景。根分区快满了,新加了100G磁盘到系统。完整操作链路是这样的:新盘分区→创建PV→扩VG→扩LV→扩文件系统。
# 1. 分区,设成8e fdisk /dev/sdb partprobe /dev/sdb # 2. 创建PV并入VG pvcreate /dev/sdb1 vgextend centos /dev/sdb1 # 3. 扩LV(把VG里所有剩余空间都给root) lvextend -l +100%FREE /dev/mapper/centos-root # 4. 扩文件系统(xfs在线扩大) xfs_growfs / # 5. 验证 df -h这里有个非常关键的点,也是很多人第一次操作时一脸懵的地方:lvextend只扩了逻辑卷的容量,文件系统不会自动跟着变大。所以必须再执行xfs_growfs /或者resize2fs,让文件系统感知到LV的新大小。
用xfs还是ext4,取决于你初始格式化时的选择。CentOS 7默认是xfs,所以上面用的xfs_growfs,它直接接收“挂载点”作为参数。如果你当初选的是ext4,那么扩大文件系统要用:
resize2fs /dev/mapper/centos-root注意resize2fs接收的是块设备路径,不是挂载点。这个区别记清楚,能省掉不少排查时间。
4.2 场景二:把/home的空间挪给根分区
我见过太多机器,装系统时默认创建了很大的/home,结果业务根本不用,/反而天天报警。这里复盘一个真实操作:原VG布局是root 20G、home 100G,目标是把home缩到10G,剩下的90G全给root。
核心难点是:home分区默认是xfs文件系统,而xfs不支持缩容。操作思路就是“备份→删掉LV→重建小LV→恢复数据→扩容root”。
# 1. 备份home数据 tar czvf /tmp/home_bak.tar.gz /home # 2. 卸载home umount /home # 3. 删除原home LV lvremove /dev/mapper/centos-home # 4. 重建一个10G的home LV lvcreate -L 10G -n home centos mkfs.xfs /dev/mapper/centos-home # 5. 恢复数据(如果是空home,这步可跳过) tar xzvf /tmp/home_bak.tar.gz -C /home # 6. 把VG剩余空间全给root lvextend -l +100%FREE /dev/mapper/centos-root xfs_growfs / # 7. 把home挂上 mount /home操作顺序非常重要:必须先备份、先缩home,扩root放最后。如果先执行lvextend -l +100%FREE,VG里所有剩余空间会被root吃掉,后面就没空间重建home了。
卸载home时如果提示target is busy,说明有进程占用,用fuser -km /home踢掉占用进程后再卸载。生产环境记得先确认业务方是否在用。
4.3 场景三:swap逻辑卷扩容
swap如果也是LVM逻辑卷,扩容同样在线化。在CentOS 7上默认/dev/mapper/centos-swap就是LVM。操作流程:
# 1. 查看当前状态 free -h swapon --show # 2. 关闭swap swapoff /dev/mapper/centos-swap # 3. 扩大LV(比如增加4G) lvextend -L +4G /dev/mapper/centos-swap # 4. 重新初始化swap文件系统 mkswap /dev/mapper/centos-swap # 5. 重新开启 swapon /dev/mapper/centos-swap # 6. 验证 free -h这里有个容易误解的地方:mkswap会格式化swap区域,相当于清空了原有交换区的内容。但swap本来就是内存的“缓存”,断电即失,所以清空没有数据损失的风险,不需要备份。
4.4 缩容的禁忌与ext4缩容流程
LVM扩容容易,缩容没那么简单,主要是因为文件系统层面对缩容的限制。
先说xfs。xfs文件系统从设计上就只支持扩大,不支持缩小。哪怕你把LV用lvreduce减少了,xfs_growfs也会直接报错,因为xfs根本无法感知“缩小”,强行缩只能损坏数据。所以对xfs,想缩只能“删掉重建”,也就是第4.2节用的办法。
再说ext4。ext4支持在离线状态下缩小文件系统,但顺序极其反直觉:先缩小文件系统,再缩小LV,跟扩容顺序相反。
# 1. 卸载 umount /dev/mapper/vg_data-lv_data # 2. 检查文件系统 e2fsck -f /dev/mapper/vg_data-lv_data # 3. 把文件系统缩到目标大小(比如50G) resize2fs /dev/mapper/vg_data-lv_data 50G # 4. 再把LV缩到合适大小(比文件系统略大一点) lvreduce -L 52G /dev/mapper/vg_data-lv_data # 5. 重新检查并挂载 e2fsck -f /dev/mapper/vg_data-lv_data mount /dev/mapper/vg_data-lv_data /data顺序错了会怎样?如果先lvreduce再resize2fs,逻辑卷已经变小,但文件系统元数据还认为它有更大空间,一旦文件系统使用超过新的LV容量,整个文件系统会损坏,数据基本救不回来。所以缩容永远记得:要么删了重建,要么严格按“文件系统在前、LV在后”的顺序。
5. 常见报错与运维笔记
5.1 刚刚创建的LV,报“设备不存在”
新创建的LV,访问/dev/vg_data/lv_data提示No such file or directory,大概率是设备映射缓存还没刷新。解决办法:
vgscan vgchange -ayvgscan是扫描VG元数据,vgchange -ay是激活所有活动VG。执行后再看/dev/mapper/下就有了。有时候lvcreate执行后一会儿消失不见,也是这个原因。
5.2 lvextend之后,df显示容量没变化
这是扩容操作中最最常见的疑惑。前面提过,lvextend只是让LV变大了,文件系统没有同步。xfs就执行xfs_growfs /挂载点,ext4就执行resize2fs /dev/mapper/vg-lv。执行完再df -h,容量才会刷新。
顺便说一句:xfs_growfs不管LV扩了多少,只要直接执行就行,它会自动扩展到LV当前的实际大小;而resize2fs如果不带参数,也会自动扩展到LV全部空间。
5.3 umount提示device is busy
一般是某个进程还留在该挂载点的工作目录下面,比如你之前cd进去过。先:
fuser -km /home该命令会终止占用/home的进程。生产环境要小心,建议先lsof | grep /home确认占用对象,再决定是否强杀。如果只是自己的shell卡在里面,cd /离开就行。
5.4 误删了LV或VG,数据能否恢复
先说结论:PV和VG的元数据还有一定恢复可能,但LV一旦被lvremove,恢复难度非常大,基本得靠备份。
误删VG后,U盘救援模式里先用pvscan看PV是否还在。只要PV还在,可以用vgcfgrestore恢复VG元数据,再vgchange -ay激活。这个操作成功率高,前提是你知道原来VG的名字。
误删LV就比较麻烦了,底层数据可能还在磁盘上,但需要手动重建同样大小的LV才能尝试找回来,还要祈祷没有新写入覆盖。所以我给所有朋友的建议都是:高危操作前先做备份。对于LVM,性价比最高的保护手段是快照。
LVM快照不是备份,但很适合做“后悔药”:
lvcreate -s -L 10G -n snap_root /dev/mapper/centos-root mount /dev/mapper/centos-snap_root /mnt-s表示创建快照,-L 10G指定快照容量。快照会记录LV在某一时刻的数据状态,数据变更时占用快照空间。如果操作出错,可以直接从快照恢复。快照空间用满的话快照会失效,所以不要长期保留,操作完尽快删除,用lvremove删除快照。
5.5 一份LVM日常维护的避坑清单
最后把零散经验整理成几条,都是实打实的教训:
| 操作 | 禁忌 | 正确做法 |
|---|---|---|
| 扩容任何LV | 只扩LV不扩文件系统 | xfs执行xfs_growfs,ext4执行resize2fs |
| 缩容xfs分区 | 试图在线缩容xfs | 备份→删除LV→重建小LV→恢复 |
| 缩容ext4分区 | 先缩LV再缩文件系统 | 先umount+resize2fs,再lvreduce |
| 写fstab | 用裸设备名如/dev/sda | 优先UUID,其次/dev/mapper/vg-lv |
| 扩root | lvextend占了全部空间,后面没余量 | 先想好其他LV是否需要预留空间 |
| 做快照 | 长期保留、空间不足 | 用完即删,操作前创建 |
我个人在实际操作中的体会是,LVM真正解决了“磁盘空间不够用又不想停机”的问题,但它的灵活性也要求更高的纪律性:操作前看一遍vgs确认VG剩余空间,扩LV之前想清楚文件系统类型,缩容之前做好备份。把这几条养成习惯,CentOS 7的LVM分区基本就再也不会出幺蛾子了。如果以后业务量继续涨,还可以在这个基础上研究thin provision和跨主机集群方案,那是另一篇故事了。