1. 场景拆解与扩容前的必读认知
先说个我在群里被问过无数次的问题:虚机磁盘在VMware里明明已经从100G调成了200G,进Ubuntu执行df -h一看,根分区还是100G,剩下那100G凭空蒸发。大部分人的第一反应是重启系统,或者怀疑VMware版本有问题,其实都不是——问题出在你根本没把新空间“接”到系统里来。
这个“接”的过程,在传统分区方案下叫扩容分区,在LVM方案下则是一套完整的PV、VG、LV操作链。而这篇文章要讲的,正是后者:当你的Ubuntu系统使用了LVM逻辑卷管理,且虚拟磁盘空间不足时,如何在VMware虚拟机环境下安全地扩展根分区容量。
先说清楚这套操作适合谁:用VMware Workstation或vSphere管理Ubuntu虚机、对LVM概念有一知半解但没完整操作过、刚装完系统发现磁盘规划太小想补救的运维和开发同学。不适合纯新手从零开始学LVM概念,但如果你愿意边看边查,也完全能跟着操作完成。
关于LVM的优缺点,我直接用一句话总结:LVM最大的价值就是“动态调整不用重装系统”,而最大的代价是你必须理解PV/VG/LV三层结构,否则出了问题容易一头雾水。网上总有人争论LVM到底好不好,我的观点很明确——在虚拟机环境里,LVM几乎就是默认答案,因为虚拟磁盘本身就是一层抽象,再套一层LVM抽象,灵活性远大于那点性能损耗。
扩展容量这件事,本质上分两步:第一步是在VMware层把磁盘空间给够,第二步是在Ubuntu系统内把空间从物理磁盘一路分配到文件系统。这两步缺一不可,而且顺序不能反。很多人只做了第一步,就觉得“已经扩容了”,其实连入口都没找到。
本文的场景设定为:你的Ubuntu安装在单个虚拟磁盘上,根分区用了LVM,现在空间告急,需要原地扩容。完整流程我将从VMware磁盘操作、系统内分区处理、LVM逻辑卷扩展、文件系统扩展四个层面依次展开,每一步都会说明原理、操作命令和常见翻车点。
2. 扩容前的状态确认与准备工作
2.1 确认你的系统确实用了LVM
动手之前,先花三十秒确认一下系统到底是不是LVM管理。很多人在网上找了半天的命令一顿操作,最后发现自己的系统压根没用LVM,白白浪费时间。
执行下面的命令查看块设备结构和挂载关系:
lsblk输出大概率会长这样:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 100G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 99G 0 part └─ubuntu--vg-ubuntu--lv 253:0 0 98G 0 lvm /看到sda2下面挂着ubuntu--vg-ubuntu--lv这种名字,且TYPE列显示为lvm,就说明你的根文件系统确实跑在LVM上。
再用LVM自己的命令确认一下:
sudo pvs sudo vgs sudo lvs这三个命令分别查看物理卷、卷组、逻辑卷的当前状态。正常情况你会看到卷组名一般是ubuntu-vg,逻辑卷名一般是ubuntu-lv(不同版本可能略有差异)。这里多提一句:Ubuntu从18.04开始,桌面版和服务器版的默认安装选项,在自动分区时几乎都会采用LVM方案,除非你在安装时手动选择了“整个磁盘”并且人为改成了传统分区。
2.2 扩容前的必要检查与备份
LVM扩展虽然支持在线操作,但在动磁盘之前,该做的检查一样不能少。
第一件事:看磁盘当前分区表和文件系统状态。
sudo fdisk -l df -hTfdisk -l看的是物理磁盘的分区分布,df -hT看的是文件系统实际挂载情况和格式类型。重点确认根分区文件系统是什么——如果是ext4,后面用resize2fs扩展;如果是xfs,就得用xfs_growfs。这两个命令不能混用,混用必报错。
第二件事:确认是否有重要数据,并评估风险。理论上说,LVM扩展操作比缩小操作安全得多——缩小需要移动数据块,中断风险大;而扩展基本是追加空间,不太容易搞坏文件系统。但“不太容易”不等于“不会”,特别是当你对分区表进行操作时,一个误操作就可能把分区表写坏。所以有条件的,建议先给虚拟机做快照。
注意:VMware Workstation的“快照”功能在虚机关机状态下做最安全。如果你做的是数据库服务器这类生产环境,建议优先选择业务低峰期操作,并且在操作前确认数据库有近期备份。
第三件事:记录当前状态。把pvs、vgs、lvs和df -hT的输出保存到文本里,万一操作中出了岔子,你可以清楚地知道原来长什么样,方便倒推恢复。
2.3 VMware层操作方式选择
在VMware里给虚拟机增加磁盘空间,有两条路:一是直接扩展现有虚拟磁盘的大小,二是新增一块虚拟磁盘挂载上去。两种方式在系统层面对应的操作路径完全不同:
- 直接扩展现有磁盘(比如把sda从100G改成200G):系统里还是只有一块物理磁盘sda,但它的尾部多出了未分配空间。你需要在这个磁盘上新建分区或扩展已有分区,再把新空间加入LVM。
- 新增一块虚拟磁盘(比如加了100G的新盘,系统里出现sdb):系统里出现了全新的物理磁盘,你需要在它上面创建PV,然后把它加入已有VG,再扩展LV。
两种方式都能达到扩展LV的目的,但操作流程和风险点不同。我个人的建议是:如果条件允许,优先选择直接扩展现有磁盘,因为这样系统里的磁盘拓扑不会变化,后续操作路径更短。但如果原磁盘的剩余扩展空间有限(比如你用的是精简置备但宿主物理磁盘快满了),那新增一块独立虚拟磁盘对宿主的存储压力反而更小。
不过,两种方式在VMware层有一个共同原则:务必在虚拟机处于关机状态时执行磁盘调整。虽然VMware Workstation也支持开机状态下的“热添加”磁盘,但系统内对SCSI设备的重新扫描有时不可靠,为了整体操作稳定,我宁愿多花一分钟关机。
3. VMware层磁盘扩展操作详解
3.1 直接扩展虚拟磁盘
在VMware Workstation中,右键虚拟机 → 设置 → 硬盘 → 工具条上的“扩展”,然后输入你想要的总容量。比如原来是100G,想扩到200G,直接输入200。
关键点在于输入的是磁盘总大小,而不是增加多少。假设你输错了,写成300,虚机里的磁盘就会直接显示成300G,但分区表和文件系统都还不知道这件事——这就是为什么系统里df -h看不到任何变化的原因。
在vSphere Web Client里,操作类似:编辑虚拟机 → 硬盘 → 重新配置 → 修改容量。
什么情况下不能直接扩展?如果你的虚拟磁盘是“独立持久”模式,并且该磁盘打过分隔符或做过RAW设备映射,在vSphere里可能无法在线扩展,只能关机操作。Workstation环境则几乎不会遇到这个问题。
扩容完成后启动虚拟机,进入系统后先重新扫描磁盘,让内核识别新的磁盘容量:
sudo partprobe sudo fdisk -l正常情况下,fdisk -l会显示磁盘总容量已经变成新的大小,但分区表的最后一个分区(通常是sda2)的结束位置并没有变化,磁盘尾部多出了一段空白空间。
3.2 新增虚拟磁盘方式
如果你选择了新增磁盘的路子,操作也简单:虚拟机设置 → 添加 → 硬盘 → 选择SCSI → 指定大小 → 完成。
这里有个小坑:新添加的磁盘在系统里的设备名不一定是sdb,取决于你的虚拟控制器。比如你原来的系统盘挂在SCSI 0:0上,新盘如果接在SCSI 0:1上,通常是sdb;但如果原来的盘在0:7,新盘却自动分配到了0:0,那系统里的设备名排序可能会颠倒。所以系统起来后,务必先lsblk看清楚哪个盘是新的,别认错盘,更不要把PV建到了系统盘上。
在系统里确认新磁盘出现的方法:
lsblk sudo fdisk -l新磁盘大概率显示为/dev/sdb,整块盘没有任何分区,大小对应你刚才添加的大小。
有人说不分区直接建PV不行吗?技术上可以,pvcreate /dev/sdb直接用整块盘也能建PV。但我从来不推荐这么干,原因后面在系统内操作部分会详细说——简单说就是分区以后,万一磁盘需要换机迁移或者做其他后续操作,分区表的存在会让你更灵活。
4. 系统内的LVM扩展完整流程(推荐路径)
接下来是本文最核心的部分。我先按直接扩展现有虚拟磁盘这条路径来走,这是最常用也最省事的方案。新增磁盘的方式我会在最后的补充小节里说明差异。
4.1 重新扫描磁盘并确认新空间
进入系统后,第一件事是让内核重新读取磁盘容量:
sudo partprobe lsblk如果你是在关机和开机之间完成的扩容,系统启动时内核会自动识别新容量,其实不一定需要partprobe。但如果你使用了热添加(虚拟机开机状态扩展了磁盘),那partprobe就非常关键了——它能让内核刷新分区表而不需要重启。
确认磁盘容量已被识别后,你会看到类似这样的lsblk输出:
sda 8:0 0 200G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 99G 0 part └─ubuntu--vg-ubuntu--lv 253:0 0 98G 0 lvm /注意sda的总容量变成了200G,但sda2分区仍然是99G,后面多出来的约101G是未分配的空白区域。
4.2 扩展分区表
到这一步有两种做法:一种是新建一个分区sda3来容纳新空间,另一种是直接扩展sda2分区,让sda2吃掉所有剩余空间。
我的建议:一定要新建分区,不要扩展已有分区。
原因有三:第一,sda2是LVM的PV所在分区,它不要求连续的磁盘空间,只要PV底层是完整的分区或者磁盘、能被LVM正常管理就行;第二,直接扩展sda2意味着要重写分区表并移动分区的结束位置,一旦中途断电或操作失误,分区表损坏的概率远大于新建分区;第三,新建分区不会影响已有分区里的任何数据,心理压力和实操风险都小得多。
用fdisk来新建分区:
sudo fdisk /dev/sda进入fdisk交互界面后,依次执行:
p # 查看当前分区表,确认sda2的结束扇区位置 n # 新建分区 # 分区类型选primary(主分区) # 分区编号默认3(即sda3) # First sector:直接回车使用默认值(紧跟现有分区之后) # Last sector:直接回车使用默认值(使用磁盘最末尾) t # 修改分区类型 # 选择分区3 # 输入 8e → Linux LVM类型 p # 再次查看分区表,确认无误 w # 写入分区表并退出关于分区类型代码再啰嗦一句:8e是Linux LVM的分区类型代码。如果不设置这个,分区也能正常使用,但fdisk -l看到的类型会是Linux或空白,某些工具和后续管理识别会出现困惑。养成好习惯,加了就完了,几秒钟的事。
分区完成后刷新分区表:
sudo partprobe lsblk此时你应该看到/dev/sda3出现了,大小约等于扩展后磁盘剩余的空间。
4.3 创建PV并加入VG
新分区创建好后,把它变成LVM的物理卷:
sudo pvcreate /dev/sda3执行后可以用pvs确认新PV是否创建成功:
sudo pvs输出应该类似:
PV VG Fmt Attr PSize PFree /dev/sda2 ubuntu-vg lvm2 a-- <99.00g 0 /dev/sda3 lvm2 --- 101.00g 101.00g可以看到/dev/sda3还没有加入任何卷组,它的VG列是空的。
接下来把新PV加入现有的卷组:
sudo vgextend ubuntu-vg /dev/sda3这里需要注意卷组名要跟你vgs看到的一致,绝大多数的Ubuntu默认卷组名是ubuntu-vg,但如果你装系统时自定义过主机名,卷组名会跟着主机名走,比如主机名叫myserver,卷组名可能就变成了myserver-vg。用vgs看一眼再下手,永远比赌记忆稳妥。
扩展成功后,vgs会显示卷组的总大小增加了,但PV那一栏会多出一行/dev/sda3。
4.4 扩展逻辑卷与文件系统
卷组空间够了,现在把逻辑卷ubuntu-lv在卷组内占用的空间加大:
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv这个命令的意思是把卷组里所有剩余空闲空间都分配给这个LV,-l +100%FREE这种写法比直接指定容量大小更实用——你不需要提前算好要加多少G,直接一把梭把剩余空间全给过去。
扩展完成后,用lvs确认一下LV大小已经变化:
sudo lvs接下来是最后一步:扩展文件系统。
- 如果文件系统是ext4(大多数Ubuntu默认):
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv- 如果文件系统是xfs(部分自定义安装场景):
sudo xfs_growfs /关键在于:resize2fs和xfs_growfs不能互换。resize2fs针对ext系列文件系统,既可以扩大也可以缩小;xfs_growfs只会扩大xfs文件系统,而且挂载点就是它的参数。执行完文件系统扩展后,用df -hT验证:
df -hT此时根分区的容量应该已经变成新的扩容后的大小,可用空间也相应增加。整个过程无需重启。
4.5 新增磁盘方式下的差异化操作
如果你走的是新增虚拟磁盘那条路,在系统里的操作会稍有不同,但核心逻辑完全一致:
lsblk # 确认新磁盘设备名,假设是sdb sudo fdisk /dev/sdb # 新建一个主分区,类型设为8e sudo partprobe sudo pvcreate /dev/sdb1 # 在分区上创建PV sudo vgextend ubuntu-vg /dev/sdb1 # 把新PV加入卷组 sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv sudo resize2fs /dev/ubuntu-vg/ubuntu-lv # 或 xfs_growfs /你可能会问:为什么新增磁盘时也要先分区,不在整块盘上直接建PV?前面提过原因,这里展开说。pvcreate /dev/sdb技术上完全可行,LVM不管你是分区还是整块盘。但问题在于:如果你以后想把这块盘从LVM里移除,或者整机迁移到别的环境,有分区表的话,你可以把sdb1的PV移走之后,再直接删分区,让这块盘恢复成普通磁盘被其他系统使用。而没有分区表的整块盘PV,想“还原”成一块普通磁盘,就得用pvremove再重新格式化,风险更大。这个操作其实不花几分钟,但能省掉后续很多麻烦,建议养成习惯。
5. 实操中的典型故障与排查技巧
5.1 扩容后df -h无变化
这是最常见的翻车现场。操作流程从头到尾走完了,lvs显示LV已经变大,df -h却纹丝不动。
原因十有八九是:文件系统没有扩容。lvextend只扩大了逻辑卷的容量,文件系统还停留在原来的大小。很多教程写到lvextend就结束了,导致大量读者卡在这一步。解决方式就是执行上面提到的文件系统扩展命令。另外注意,执行resize2fs之前确认LV已经是新的大小,否则会提示无空间可扩展。
另一个不太常见但确实存在的原因:你把resize2fs跑错了设备。比如你的根分区在/dev/ubuntu-vg/ubuntu-lv,但你却对/dev/sda2执行了resize2fs,当然不会生效。文件系统扩展对象是LV设备节点,不是底层物理分区。
5.2 fdisk操作时提示分区表繁忙
在执行partprobe或重启后,fdisk有时会提示类似“磁盘正忙”或“内核仍然使用旧分区表”的错误。
通常发生场景:你对正在使用的磁盘(比如挂载了根分区的sda)执行了fdisk修改,写完分区表后partprobe没能立即刷新。
处理办法:先确认没有其他进程在占用这个分区,比如用lsof /dev/sda*查一下。如果确实没有进程占用但还是刷新不了,最简单的做法是重启虚拟机——你是在VMware环境里,重启也就几十秒的事,没必要在这上面耗时间。
提醒:如果重启前你已经在fdisk里写了分区表,重启后
lsblk一定能看到新分区sda3,这一步不需要担心。
5.3 误操作:扩展了某个不相关的LV
有些系统上除了根LV之外,还可能有swap的LV,或者你之前手动创建过其他LV。执行lvextend时,一定要明确指定LV名称。我就见过有人把lvextend -l +100%FREE执行到了swap LV上——虽然没啥严重后果,但你卷组的全部空闲空间都被swap吃掉了,根分区还是100G,等于白操作了一遍。
解决方式也不难:如果已经扩到swap上了,先lvreduce把swap的LV恢复原大小,然后再给根LV扩展。但请注意:lvreduce是有数据风险的操作,务必先确认swap LV上没有重要的文件系统数据(swap的pv/fs信息很明确,一般不会有数据),否则不要贸然缩小。如果对自己操作没把握,宁愿重启回滚快照,也别冒险。
5.4 在线扩容后的性能波动
LVM在线扩容本身不会导致明显性能下降,但如果你在系统IO繁忙时(比如数据库正在批量写入)执行了resize2fs,文件系统元数据的更新可能会导致短时间的IO卡顿。所以我的建议是:尽量在业务低峰期操作,并在扩容前用sync命令强制把缓存写入磁盘。
另外,如果虚拟机用的是精简置备磁盘,VMware层扩容后宿主物理磁盘的可用空间可能并不充裕。LVM层面看到的是虚拟磁盘规格变大了,但实际IO落到宿主时,如果宿主物理存储满了,虚拟机可能会直接卡死。建议扩容前先看一眼宿主的存储空间,别把虚机空间加得比宿主的实际剩余空间还大。
5.5 根分区几乎占满时的扩容注意事项
如果你是在磁盘只剩几个G可用空间的情况下进行扩容,流程并没有区别,但有一个细节要提醒:执行resize2fs时,文件系统需要临时分配一些元数据空间。如果根分区已经爆满,resize2fs可能因为连临时空间都腾不出来而报错。这种极端情况下,建议先清理一些不必要的缓存文件,腾出5%~10%的余量再操作。虽然LVM扩展大部分情况下不受影响,但在极端环境里多留点余量总归是稳妥的。
5.6 扩容后虚拟机无法启动的紧急恢复
这种情况比较少见,但一旦遇到,心里要有个底。
可能原因包括:分区表写入过程中虚拟机异常断电、partprobe刷新后内核状态异常、fdisk里误删了已有分区等。
应急思路如下:
- 用Ubuntu安装ISO启动,进入Live环境(试用Ubuntu);
- 挂载根文件系统,检查数据是否完好;
- 用
vgs、lvs确认LVM状态是否正常; - 如果只是分区表的问题,用
fdisk重新补上遗漏的分区(分区起始扇区可以从分区表备份或testdisk恢复); - 如果数据盘没坏但系统起不来,重点查
/etc/fstab里挂载配置是否有问题。
本质上的核心教训:分区表和LVM元数据的风险,通常只在最坏情况下暴露。平时多用pvdisplay、vgdisplay这些命令熟悉你系统的元数据布局,关键时刻能救你一命。
6. 扩展后的验证及日常维护建议
6.1 完整验证清单
扩容完成后,建议按以下清单逐项验证,别只看df -h一个输出就完事:
df -hT:根分区大小和可用空间是否符合预期;lsblk:分区结构和LVM层级关系是否正常;pvs:所有PV状态是否为a--(active);vgs:VG大小是否符合预期,剩余空间是否为0(如果你把全部空间都分配给了根LV);lvs:LV大小正确,状态为-a-(active);mount | grep ' / ':根分区挂载正常无报错。
另外建议在扩容后重启一次虚拟机,确认重启后LVM能正常激活、挂载,文件系统检查无误。这次重启不是必须的,但对于重要虚拟机来说,早发现早处理,比日后哪天突然重启才发现起不来要好得多。
6.2 磁盘监控建议
容量扩展是一次性操作,但运维是长期的事。建议在Ubuntu上做基础的磁盘监控,避免再次出现“空间耗尽后才反应过来”的情况。
最简单的方式就是cron加脚本定期统计使用率,超过阈值就发通知。这里给一个精简版示例,把下面内容保存为/usr/local/bin/disk_check.sh:
#!/bin/bash THRESHOLD=80 USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$USAGE" -gt "$THRESHOLD" ]; then echo "$(date): Root partition usage ${USAGE}% exceeds ${THRESHOLD}%" >> /var/log/disk_alert.log fi加了执行权限后,在crontab里每半小时跑一次:
*/30 * * * * /usr/local/bin/disk_check.sh这个脚本非常简陋,但够用。你完全可以根据自己的环境扩展成邮件提醒或者接入告警平台。核心目的不是告警本身,而是让你对磁盘增长趋势心里有数,哪天看到告警就知道该扩容或清理了。
6.3 后续扩展方向的思考
如果你做的是一次性扩容,到这里就能收工了。但从长远看,我建议想清楚这样几个问题:
第一,这次扩容后,你的卷组内是否还有剩余空间?如果还有,那下次扩展就只需要lvextend加resize2fs两步,连分区都不用碰。这也是初始规划时不要把所有空间全部分配给LV的原因——留一点弹性在VG里,等于给未来留了缓冲。
第二,你的虚拟磁盘本身是否还有扩展余地?如果VMware宿主磁盘趋近饱和,那下次扩容可能要考虑新增独立数据盘,而不是继续放大系统盘。
第三,根分区和数据的存放逻辑是否合理?很多人的根分区之所以不够用,是因为把所有业务数据都堆在了根分区。如果条件允许,把数据库目录、容器数据目录这类大体积内容挂载到独立分区或独立磁盘,根分区扩容的频率会大大降低。
按照我个人多年的运维习惯,LVM是一次投入、长期受益的方案。首次安装系统时花五分钟规划好磁盘分区结构,后面扩容基本都是标准化的四条命令:pvcreate、vgextend、lvextend、resize2fs。这套流程我也会定期在测试环境里演练一遍,因为某些细节(比如分区类型代码、卷组名)太久不碰真的会忘。文档可以帮你捡起知识点,但亲手操作过的肌肉记忆才是真正的保险。希望这篇操作说明能让你在真正需要扩容的那天,从容地敲下每一个命令。