1. 为什么你的Ubuntu根目录总是不够用?LVM来救场
不知道你有没有遇到过这种情况,本来装系统时觉得给根目录分个50G绰绰有余,结果用着用着,某天突然发现系统弹出了“磁盘空间不足”的警告。尤其是当你用Ubuntu做开发机或者服务器,Docker镜像、日志文件、各种开发工具链一装,空间就像被黑洞吸走一样,消失得飞快。我自己的几台虚拟机就经常遇到这个问题,每次都得停下来折腾扩容,特别影响效率。
传统的磁盘分区方式,比如直接用fdisk分一个/dev/sda1给根目录,一旦分好了,大小就固定死了。想扩容?要么用一些有风险的工具去调整分区边界,要么就得备份数据、重装系统,过程繁琐不说,还容易丢数据。这对于需要7x24小时运行的服务器来说,简直是噩梦。
这时候,LVM(Logical Volume Manager,逻辑卷管理)的优势就体现出来了。你可以把它想象成一个超级灵活的“磁盘空间池”。它把一块或多块物理硬盘(或者分区)先打成“物理卷”(PV),然后把这些物理卷扔进一个叫“卷组”(VG)的大池子里。最后,你从这个池子里按需划出“逻辑卷”(LV)来使用,比如挂载成根目录/或者/home。当空间不够时,你只需要往池子里加新的物理硬盘(或者扩展现有物理卷),然后动态调整逻辑卷的大小就行,整个过程不需要重启,也不需要卸载文件系统,业务可以照常运行。
这篇文章,我就手把手带你走一遍最经典的Ubuntu LVM动态扩容实战。场景很具体:你的Ubuntu系统根目录快满了,而你的系统当初是用LVM安装的(现在很多Ubuntu Server的默认安装方式就是LVM)。我们将从虚拟机层面添加硬盘空间开始,一路操作到你的根目录/可用空间翻倍,把PV、VG、LV这几个概念和操作揉碎了讲清楚。即使你之前没怎么接触过LVM,跟着做一遍,也能彻底搞明白。
2. 动手之前:搞懂LVM的核心三件套
在开始敲命令之前,咱们得先花几分钟把LVM里最关键的三个概念捋清楚。这就像玩积木,你得先认识每一块积木是干嘛的,才能搭出想要的房子。理解了它们,后面的操作就完全是按图索骥,不会迷路。
物理卷(Physical Volume, PV):这是最底层的一块“砖”。它可以是整个物理硬盘(比如/dev/sdb),也可以是硬盘上的一个分区(比如/dev/sda3)。但光是一块硬盘或分区还不够,你需要用pvcreate命令对它进行“初始化”,打上LVM的标记,它才能成为一块合格的“LVM砖块”。你可以用pvs或pvdisplay命令查看系统里有哪些PV。
卷组(Volume Group, VG):你可以把VG看作一个“建材仓库”。这个仓库专门存放PV这种“砖块”。一个VG可以由一个或多个PV组成。比如,你可以把/dev/sda3和/dev/sdb这两个PV都加入一个叫ubuntu-vg的卷组里。这样,ubuntu-vg这个仓库的总容量就是这两个PV的容量之和。VG是LVM中承上启下的关键层,它把底层的物理存储资源聚合了起来。查看VG的命令是vgs或vgdisplay。
逻辑卷(Logical Volume, LV):这才是我们最终用来创建文件系统、挂载使用的部分,相当于从“建材仓库”里领出材料,盖好的“房间”。比如,我们可以从ubuntu-vg这个仓库里,划出30G空间,创建一个叫ubuntu-lv的逻辑卷,然后把它格式化成ext4文件系统,挂载到根目录/。一个VG里可以创建多个LV,非常灵活。查看LV的命令是lvs或lvdisplay。
它们三者的关系,我画个简单的图在脑子里你就明白了:多个PV(砖块) -> 组成一个VG(仓库) -> 从VG中划分出多个LV(房间) -> LV格式化后挂载使用(入住房间)。
那么,动态扩容的链条也就清晰了:假设我们的根目录/挂载在/dev/ubuntu-vg/ubuntu-lv这个LV上。现在空间不够了,我们的大致路线是:
- 源头加水:给虚拟机添加一块新硬盘,或者扩展现有硬盘的容量。
- 砖块入库:将新增的硬盘空间创建为新的PV,或者扩展已有PV的大小。
- 扩充仓库:将新的PV加入现有的VG,或者让VG识别已有PV的新增空间。
- 扩大房间:从已经变大的VG里,分配更多空间给我们的LV。
- 房间装修:最后,让LV上的文件系统(如ext4)识别到变大的空间。
接下来,我们就一步步实操。我会以最常见的VMware虚拟机环境为例,假设我们是通过扩展原有分区(比如/dev/sda4)来扩容的,这也是很多朋友会遇到的情况。
3. 第一步:为虚拟机“插入”一块更大的“硬盘”
既然是虚拟机环境,扩容的第一步当然是在虚拟化管理层面进行操作。这就像给你的电脑主机加装一块新硬盘,只不过操作是在VMware或者VirtualBox的图形界面里完成的。
以VMware Workstation为例,你需要先关闭Ubuntu虚拟机的电源。然后找到虚拟机的设置,选择“硬盘”选项。这里通常会有一个“扩展”或“扩容”的按钮。点击它,输入一个比当前更大的容量,比如从原来的40G扩展到60G。这个过程VMware会在后台处理,速度很快。完成后,启动虚拟机。
重要提示:这里有一个非常关键的细节。虚拟机管理软件只是“承诺”给了虚拟机一块更大容量的硬盘。但是,虚拟机内部的操作系统(也就是我们的Ubuntu)此时并不知道这个变化。我们还需要在操作系统内部,告诉它:“嘿,我们的硬盘变大了,快来重新认识一下它。” 这就是为什么我们接下来要使用fdisk工具的原因。
如果你用的是物理服务器,那么这一步就对应着:你实际在服务器主机的硬盘槽位上插入了一块全新的物理硬盘。对于操作系统来说,新硬盘会被识别为类似/dev/sdb这样的设备名。我们后面的操作思路是类似的,只是操作对象从/dev/sda的某个分区,变成了全新的/dev/sdb设备。
4. 第二步:让系统认识更大的空间——使用fdisk调整分区
现在,我们登录到Ubuntu系统。首先,用lsblk或fdisk -l命令看一下当前的磁盘情况。你应该能看到你的系统盘(比如/dev/sda)的总容量已经变成了你刚才扩展的大小(例如60G),但是下面的分区表可能还显示着旧的分区信息。
我们的目标是扩展那个作为LVM物理卷的分区。假设之前LVM用的是/dev/sda4这个分区。注意:这个操作有一定风险,请务必在操作前确认分区号,并且如果有重要数据,建议先备份。不过,因为我们只是扩展分区到硬盘的末尾空闲空间,并不移动现有数据的起始位置,所以风险相对较低。
下面是详细的fdisk操作步骤和解释,我会尽量把每个命令的作用说清楚:
sudo fdisk /dev/sda这会进入fdisk的交互式命令行。首先,输入p并回车,打印当前的分区表。仔细记录下你要操作的分区(例如/dev/sda4)的起始扇区(Start sector)。这个数字至关重要,我们后面新建分区时必须使用完全相同的起始扇区,否则数据就丢了。
接下来,输入d并回车,删除分区。它会问你分区编号,输入4(对应/dev/sda4)并回车。别紧张,这个删除操作目前只发生在内存里,还没有写入磁盘。此时再用p查看,会发现/dev/sda4消失了。
现在,输入n并回车,创建新分区。它会问你是创建主分区(p)还是扩展分区(e),我们通常选p(主分区)。然后它会提示你输入分区号,直接回车默认(应该是4)。接下来是最关键的一步:输入起始扇区。这里必须输入你刚才记下来的那个起始扇区数字,确保一模一样。如果直接回车用默认值,一定要确认默认值就是原来的起始扇区。
最后是输入结束扇区。这里我们可以直接回车,使用默认的最大值(即硬盘的最后一个扇区)。这样,新分区/dev/sda4就会从原来的起始位置一直延伸到硬盘末尾,占用了所有新增的空间。
再次输入p确认一下新分区表,确保/dev/sda4的起始扇区没变,结束扇区变大了。确认无误后,输入w并回车,将分区表写入磁盘并退出。系统可能会提示你需要重启或者使用partprobe命令让内核重新读取分区表。我们可以不用重启,执行一下:
sudo partprobe /dev/sda或者
sudo partx -u /dev/sda现在,用lsblk再看一下,你应该能看到/dev/sda4的容量已经变大了。但是,如果你运行pvdisplay查看物理卷,会发现它的尺寸可能还没变。别急,这是因为LVM层还没感知到底层分区的变化。下一步我们就来解决这个问题。
5. 第三步:通知LVM——“砖块”变大了(PV扩容)
我们的“砖块”(PV)/dev/sda4在物理层面已经变大了,但管理它的LVM还不知道这个好消息。我们需要用pvresize命令来通知它。
这个命令非常简单,就一行:
sudo pvresize /dev/sda4pvresize命令会自动检测/dev/sda4这个块设备的实际大小,并更新LVM中记录的该物理卷的元数据信息。执行速度很快,几乎是瞬间完成。
执行完成后,我们立刻用pvdisplay /dev/sda4来验证一下:
sudo pvdisplay /dev/sda4在输出信息里,找到“PV Size”这一行。你会发现它的值已经更新了,变成了新的、更大的容量(比如从<19.00 GiB变成了<39.00 GiB)。同时,注意看“Total PE”和“Free PE”这两项。“PE”是物理盘区(Physical Extent),是LVM管理空间的最小单位,默认大小是4MB。如果“Free PE”还是0,说明空间虽然变大了,但还没有空闲的盘区可供分配。这是因为我们只是扩大了PV,还没有把新增的空间“分配”给上层的卷组(VG)和逻辑卷(LV)。
这就好比你的仓库(VG)里原来堆满了砖块(PV),现在每块砖都变长了,但仓库管理员(LVM)还没来得及把这些“长出来的部分”标记为可用库存。下一步,我们就要让仓库管理员知道这些新增的库存。
6. 第四步:从“仓库”划拨空间给“房间”(VG与LV扩容)
在LVM的架构里,PV的扩容会自动反映到其所属的VG上。也就是说,当你用pvresize扩大了PV后,它所在的VG的“总容量”和“空闲容量”也就随之增大了。我们可以用vgdisplay命令来确认这一点:
sudo vgdisplay ubuntu-vg查看输出中的“VG Size”和“Free PE / Size”,应该能看到空闲空间增加了。如果vgdisplay显示空闲空间确实变大了,那我们就可以进行最关键的一步:扩展逻辑卷(LV)。
我们使用lvextend命令来给LV增加空间。这里有两种指定大小的方式:
-L +20G: 表示在现有LV大小的基础上增加20G。-L 40G: 表示将LV的总大小设置为40G。
我强烈建议使用第一种-L +[大小]的方式,更直观,也不容易出错。假设我们要把根目录对应的LV增加20G,命令如下:
sudo lvextend -L +20G /dev/ubuntu-vg/ubuntu-lv这里的/dev/ubuntu-vg/ubuntu-lv是你的LV设备路径。如果你不确定是哪个,可以用df -h查看根目录/挂载的设备,或者用lvdisplay查看所有LV信息。
命令执行成功后,再用lvdisplay /dev/ubuntu-vg/ubuntu-lv查看,你会发现“LV Size”已经变大了。但是,如果你立刻再用df -h查看根目录的可用空间,会发现一个“诡异”的现象:根目录的大小居然没变!
别慌,这是完全正常的。我们目前只是把“房间”(LV)的墙体向外推了,扩大了建筑面积。但是“房间”内部的地板(文件系统)还没有铺到新扩大的区域。所以操作系统通过df命令看到的,仍然是旧的地板面积。我们需要最后一步,来铺开地板。
7. 第五步:最后的临门一脚——扩展文件系统
这是让系统最终能用上新空间的最后一步,也是最容易忘记的一步。我们需要扩展LV上的文件系统。对于Ubuntu默认的ext4文件系统,我们使用resize2fs工具。它的强大之处在于支持在线扩容(online resizing),也就是说,你不需要卸载根目录/,甚至不需要进入单用户模式,直接运行即可。
命令非常简单,直接对LV设备操作:
sudo resize2fs /dev/ubuntu-vg/ubuntu-lvresize2fs命令会自动检测LV当前的大小,并将文件系统扩展到填满整个LV。你会在输出中看到类似“on-line resizing required”和“The filesystem … is now … blocks long.”的信息,表示它正在在线调整大小。
稍等几秒钟,操作完成后,再次运行df -h。这次,你应该会看到令人欣喜的结果:根目录/的“Size”列已经变成了扩容后的新容量,而“Avail”(可用空间)也大大增加了!
这里有一个超级实用的技巧:如果你记不住resize2fs这个命令,或者怕搞错顺序,其实lvextend命令提供了一个-r(--resizefs)选项。你可以把第四步和第五步合并成一条命令:
sudo lvextend -L +20G -r /dev/ubuntu-vg/ubuntu-lv这条命令会在扩展LV之后,自动调用相应的文件系统扩容工具(对ext3/ext4是resize2fs,对xfs是xfs_growfs)。这对于新手来说非常友好,能避免忘了最后一步的尴尬。我后来在给团队写运维手册时,就强烈推荐大家使用这个-r参数,省心又安全。
8. 避坑指南与进阶技巧:我踩过的那些雷
走通了完整的流程,是不是觉得LVM扩容也没那么难?但实际生产中,情况可能更复杂一些。我把自己和同事们踩过的一些坑总结一下,希望能帮你少走弯路。
坑一:分区类型标识(Partition Type)。在用fdisk创建新分区时,除了起始扇区,还有一个地方要注意:分区的系统ID。对于LVM使用的分区,其类型应该是Linux LVM(对应ID是8e)。在fdisk里,输入t命令可以修改分区类型。如果你扩容后发现pvresize报错,可以检查一下分区类型是否正确。
坑二:空间计算与单位。在lvextend命令中,-L +20G和-L 20G是天壤之别。一个是增加20G,一个是设置总大小为20G(如果原来有30G,这命令一下就会丢失10G空间和数据!)。另外,G和g是通用的,但要注意单位是G(GB)、M(MB)还是T(TB)。最稳妥的方法是,先用vgdisplay看看VG里有多少空闲空间(Free PE / Size),然后再决定分配多少。
坑三:XFS文件系统的特殊处理。如果你的Ubuntu系统根目录用的是XFS文件系统(一些较新的版本或特定安装选项可能会用),那么最后一步的命令就不是resize2fs了,而是xfs_growfs。而且xfs_growfs命令的对象是挂载点,而不是设备文件。命令是这样的:
sudo xfs_growfs /同样,使用lvextend -r命令可以自动适配XFS文件系统,非常方便。
进阶技巧:预留空间与监控。为了避免频繁扩容,在创建LV时可以考虑不要一次性把VG的空间用光,留一些“备用金”。同时,建议设置简单的磁盘空间监控,比如用cron定时任务跑df -h,把结果发到邮箱或者监控平台,在空间使用率达到80%或90%时就提前预警,给自己留出从容的操作时间。
最后的大杀器:快照(Snapshot)。这是LVM另一个超级好用的功能。在进行像扩容分区这种有风险的操作之前,可以给LV创建一个快照。快照几乎瞬间完成,并且只占用很少的空间。如果操作失误,你可以立即回滚到快照点,秒级恢复。创建只读快照的命令是lvcreate -s -n snap_name -L 5G /dev/vg_name/lv_name。这就像是给系统拍了一张“后悔药”照片,对于生产环境来说,是个必备的安全措施。