搞虚拟机最烦的一件事,就是磁盘当初分区的时候没给足,结果用着用着就满了。我最近就在VMware里遇到这个情况,ubuntu 22.04的虚拟机跑一个编译任务,日志文件蹭蹭涨,根分区直接给干到98%。你说重新建一台吧,环境重配一遍太折腾;不扩容吧,系统随时可能因为写不进东西直接崩掉。所以只能老老实实走一遍VMware虚拟机磁盘扩容流程。
先说清楚这篇文章解决什么问题:VMware Workstation(16/17都适用,其他版本同理)里的ubuntu 22.04虚拟机,磁盘空间不够了,想要在不重装系统、不丢失现有数据的前提下,给虚拟磁盘增加容量,并且让Ubuntu系统真正能用上这些新增空间。适合的人群是:已经装了ubuntu虚拟机、Linux基础一般、第一次做磁盘扩容的开发者或运维同学。接下来我把整个流程拆开讲,包括VMware层的操作、Ubuntu层的分区处理、文件系统扩容,以及我踩过的几个坑。
1. 扩容前的准备工作与整体思路
1.1 为什么需要磁盘扩容以及扩容的原理
虚拟机磁盘扩容本质上分两个层面:首先是宿主机上那个虚拟磁盘文件(vmdk)本身要变大,然后才是客户机操作系统(也就是ubuntu 22.04)里面分区和文件系统要感知并利用这个变大的空间。
VMware里面点“扩展磁盘”按钮,改的只是vmdk的容量上限,它把磁盘尾部未分配的空间多划出来一段。但ubuntu系统里看到的还是原来的分区大小,因为分区表里根本没有记录这些新增空间。所以很多新手卡在“我在VMware里已经扩容了20G,但Ubuntu里df -h看还是老样子”这一步,其实就是忽略了这个两段式原理。
讲的通俗一点:VMware扩展磁盘,相当于你给硬盘盒换了一个更大的硬盘,但硬盘盒里面的分区还是老结构,新空间就是一块“未分配”的空白区。Ubuntu系统默认只管理分区表里登记过的分区,不会自动去认这块空白区。所以扩容必须分成“宿主机改vmdk大小”和“客户机改分区表+文件系统”两步走,缺一不可。
1.2 扩容前的确认事项清单
动手之前,我建议花两分钟确认下面几件事,不然中途容易翻车:
- 宿主机剩余磁盘空间是否充足:VMware扩展磁盘时,要确认宿主机磁盘有足够空间容纳扩容后的vmdk大小。比如原来vmdk分配100G,你要扩到160G,宿主机至少还能腾出60G以上的空间,否则扩容会失败。
- 虚拟机是否关机:VMware里扩展磁盘必须是在虚拟机关机状态下操作,开机状态扩不了。不过在ubuntu系统内部做文件系统扩容时,可以不用关机,后面会讲。
- 检查虚拟机是否有快照:如果虚拟机有快照,VMware里扩展磁盘时会有提示,一般建议扩容前先删除快照或者先对快照处理一下,否则vmdk结构复杂,扩容风险大,后面我会专门讲这个坑。
- 确认当前分区表类型:MBR还是GPT。MBR最大支持2T,GPT才能支持2T以上。ubuntu 22.04默认用GPT的居多,但也不能一概而论,先用命令确认一下再操作。
确认完这些,就可以进入实际操作环节了。整个过程我预估耗时在十到二十分钟左右,绝大部分时间花在等待扩容和格式化上,真正敲命令的时间并不长。
2. VMware层面对虚拟磁盘进行扩容
2.1 虚拟机设置中扩展磁盘的具体操作
在VMware Workstation中打开虚拟机设置,路径是这样:选择虚拟机 -> 右键“虚拟机设置”(或者点击菜单栏里的“编辑虚拟机设置”)-> 切换到“硬件”选项卡 -> 点击“硬盘” -> 右侧会有“磁盘信息”和“实用工具”区域,里面有一个“扩展”按钮。
点击“扩展”后,会弹出对话框让你输入扩展后的最大磁盘大小,注意这个值是你期望的最终大小,不是“增加多少”。比如原来是40G,你想再加20G,这里要填60。系统会给出一个最大可扩展范围,一般情况下不要超过宿主机剩余空间。填好后点击“扩展”,等待进度条走完即可。
整个过程很快,一般几十秒到几分钟,取决于磁盘大小和宿主机的磁盘性能。完成后点击确定关闭设置窗口,这时候vmdk文件容量已经变大了,但ubuntu系统内还没有体现。
有个细节值得说:如果你在VMware界面里发现“扩展”按钮是灰色的,多半是虚拟机处于开机状态,或者虚拟机设置了加密磁盘。前者关机即可解决,后者需要先在虚拟机设置里取消磁盘加密,这个比较少见,但遇到过的人会卡得很痛苦。
2.2 扩容生效的几个关键细节
第一,扩展过程中一定别去动宿主机的其他写入操作,尤其是别在扩展的同时跑一些大文件拷贝任务。我遇到过扩展到一半宿主机空间不足导致vmdk损坏的情况,虽然概率不高,但一旦发生就得靠备份恢复了。
第二,扩展后如果虚拟机有多个快照,VMware会在界面上提示“此虚拟机具有快照,无法扩展”。当时我的做法是先把快照都合并掉(删除快照),然后再执行扩展。删除快照最好在虚拟机关机状态下进行,并且要确保对应的快照已经不再需要,因为合并后会丢失快照点。
第三,如果你用的是共享虚拟磁盘或者RDM(裸设备映射),就不能在Workstation界面上直接扩展。不过正常单机使用场景基本不涉及这些,知道有这个限制就行。
第四,扩展完成后建议顺手在宿主机上看一眼vmdk文件的大小变化,确认它确实增大了。有时候因为磁盘类型是精简置备(thin provisioning),文件本身的大小不会立刻变成目标值,而是随使用逐渐增长。这个不影响扩容结果,只是让一些“看文件大小”判断的朋友虚惊一场。
3. Ubuntu系统层面对新增空间进行分区规划
3.1 确认系统磁盘设备信息
VMware层面扩完后,启动ubuntu 22.04虚拟机,登入终端。第一件事是用lsblk或者fdisk -l看一下现在的磁盘状态。
lsblk正常情况下你会看到类似这样的输出:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS sda 8:0 0 60G 0 disk ├─sda1 8:1 0 1M 0 part ├─sda2 8:2 0 1G 0 part /boot └─sda3 8:3 0 39G 0 part └─ubuntu--vg--ubuntu--lv 253:0 0 39G 0 part /注意这里sda的总大小已经显示60G了,但sda3分区还是39G,根文件系统也还是39G。这个差异就是新增的约21G空间。接下来我们要做的,是把这段未分配空间变成可以用的分区和文件系统。
这里我多说一句:有的朋友会发现自己的设备名是nvme0n1而不是sda,这是因为虚拟磁盘类型选的是NVMe而非SCSI。操作逻辑完全一样,只是把命令里的/dev/sda替换成/dev/nvme0n1,分区名变成nvme0n1p1这样的格式,别被名字吓到。
3.2 使用fdisk创建新分区
分区操作有两种常见思路:一种是把新增空间单独划成一个新分区,挂载到某个目录,比如/data;另一种是把新增空间合并到现有根分区。这里先讲第一种,更简单也更稳妥,适合大多数场景。
使用fdisk操作:
sudo fdisk /dev/sda进入fdisk交互界面后,依次输入:
- 输入p,查看当前分区表
- 输入n,创建新分区。此时fdisk会提示分区号、第一个扇区等信息,一般直接按回车接受默认值即可,最后一个扇区默认会用到磁盘末尾
- 输入p,再次查看分区表,确认新分区(比如sda4)已经创建
- 输入w,写入分区表并退出
注意如果磁盘是GPT分区表,fdisk会询问是否创建GPT分区,跟着默认走就行。写入完成后,用partprobe让内核重新读取分区表:
sudo partprobe如果有报错说分区忙,说明有文件系统还在使用这个设备,重启一下再执行也可以。
这里有个特别容易犯的错:fdisk输出里的扇区数,很多人看着头晕,干脆乱填。实际上你只需要记住,创建分区时直接按回车接受默认的起始扇区和结束扇区,系统会自动把新分区放到可用空间的头部和尾部,根本不用手动计算。我见过有人非要自己填数字,结果把原有分区给覆盖了,数据全没,太冤了。
3.3 分区类型与文件系统选择
新分区创建后,还要格式化。选择什么样的文件系统,取决于你的用途。ubuntu 22.04默认数据盘用ext4最省心,如果你想以后方便在不同Linux发行版之间迁移,也可以选xfs。这里我以ext4为例:
sudo mkfs.ext4 /dev/sda4如果新增空间大于2T,注意分区表必须是GPT,且格式化时建议加上-T largefile参数,或者用xfs,否则ext4在大容量下的inode分配策略效率不高。当然,单机虚拟机一般到不了这个规模。
格式化完成后,可以给分区创建一个标签,方便后面挂载时识别。我用的是:
sudo e2label /dev/sda4 data格式化是个不可逆操作,执行前务必再三确认分区编号没有写错。最好的确认方式就是lsblk再看一遍,认清sda4到底对应哪一段空间。多说一句,如果你和我一样有强迫症,格式化的时候用-m 0参数把保留块比例降为零,对纯数据分区来说能省出不少空间,比如10T数据盘能多出几十G可用容量,还是挺香的。
4. 文件系统扩容与挂载配置
4.1 格式化新分区并创建挂载点
接下来的事情就简单了,把新分区挂载到目录上。先创建挂载点,比如/data:
sudo mkdir -p /data sudo mount /dev/sda4 /data这时候再执行df -h,你应该能看到/dev/sda4已经挂载在/data上,容量大概就是你新增的空间大小,可能略小一点,因为文件系统本身要吃掉一部分metadata空间,这是正常现象。
比如你新增了20G,格式化后df -h显示的可能是19.2G或者18.6G,具体数值取决于块大小和文件系统保留块。很多人看到这个数值会以为扩容“缩水”了,其实没有,这是文件系统自身的开销,任何分区方案都一样。
4.2 自动挂载配置(fstab)
手动挂载重启后就失效了,所以要把挂载信息写入/etc/fstab。先获取分区的UUID:
sudo blkid /dev/sda4会输出类似这样的一行:
/dev/sda4: UUID="a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx" TYPE="ext4"然后编辑/etc/fstab,在文件末尾追加一行:
echo 'UUID=a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data ext4 defaults 0 2' | sudo tee -a /etc/fstab加完之后建议用mount -a检查一下配置是否语法正确:
sudo mount -a这一步很重要,很多人fstab写错了,下次开机直接进不去系统,或者至少卡在紧急模式。别问我怎么知道的,我在别的机器上就踩过这个坑,所以强烈建议改完fstab先验证。
顺带讲一下fstab最后一列那个“2”的含义:0表示不检查,1表示最先检查(一般只有根分区用),2表示在根分区之后检查。数据盘填2是常规做法,但不是必须,填0也不会有问题,只是开机时少了文件系统自检环节。
4.3 直接扩展根分区的方法(growpart + resize2fs)
如果你不想新建分区,而是想把新增空间直接合并到现有根分区,做法也不复杂。前提是你的根分区在虚拟磁盘的最后一个分区,并且在分区表里它后面还有空闲空间。这种情况下用growpart和resize2fs就能在线扩容。
安装工具(如果缺失):
sudo apt update sudo apt install cloud-guest-utils然后执行:
sudo growpart /dev/sda 3这条命令会把sda3这个分区扩展到磁盘末尾,也就是吃掉新增的未分配空间。注意growpart的语法是“设备 分区号”,中间有空格,不是/dev/sda3这种写法。
扩展完分区后,查看当前根文件系统的设备名:
df -h /如果根分区对应的是/dev/mapper/ubuntu--vg--ubuntu--lv,那说明系统用了LVM,可以先用lvextend扩展逻辑卷,再执行resize2fs;如果直接是/sda3,那么直接resize2fs即可:
sudo lvextend -l +100%FREE /dev/mapper/ubuntu--vg--ubuntu--lv sudo resize2fs /dev/mapper/ubuntu--vg--ubuntu--lv执行完成后,再df -h看一下,根分区的容量应该已经变大了。
这里提醒一句:LVM逻辑卷的lv名称在ubuntu 22.04上默认带两个连字符的转义写法,实际上LVM创建时名字是ubuntu-vg/ubuntu-lv,映射到/dev/mapper/ubuntu--vg--ubuntu--lv是因为udev对连字符做了转义。用lsblk看清楚再操作,别一股脑照抄命令。
还有一个细节:growpart扩展分区后,你可能会看到内核提示“分区表已改变,需要重启”。如果出现这个提示,说明内核还没完全接受新分区表,这时候resize2fs会失败或者无效。稳妥做法是先reboot一次再执行resize2fs,别嫌麻烦。我在没有LVM的纯净ubuntu系统上测试过,有时不重启也能直接resize,但既然提示了,还是重启一下心里踏实。
5. 常见问题与排查技巧实录
5.1 虚拟机快照导致扩容失败的坑
我在做这次扩容时,第一反应是去VMware界面点“扩展”,结果弹窗提示“无法扩展磁盘,因为此虚拟机具有快照”。当时这台虚拟机确实留了两个快照,是为了测试某个软件环境备份用的。没办法,只能先删除快照。
删除快照的操作在“虚拟机 -> 快照 -> 快照管理器”里,选中对应快照点“删除”,VMware会把快照文件合并到主vmdk上。这个合并过程也是需要时间的,而且一定要在虚拟机关机状态下做。合并完成后,再回去点“扩展”就正常了。
这个坑特别影响新手,因为很多人根本不知道有就不能扩展磁盘。以后如果遇到扩容需求,建议在创建虚拟机的时候就规划好,快照要么不留,要么等在扩容前统一清理。
我后来为了写这篇总结,又专门在一个带快照的测试虚拟机上试了一次,确认弹窗提示信息在不同版本VMware里都差不多。如果你用的是VMware Workstation Pro 17,记得在删除快照后看一眼虚拟机的vmdk文件列表,确认不存在-snapshot之类的增量文件后再扩容。
5.2 磁盘空间显示未生效的排查思路
有朋友问,VMware里扩展了,ubuntu系统里lsblk也能看到总大小变了,但df -h看到的跟原来一样,这是怎么回事?
这种情况多半发生在只扩容了分区表没创建新分区,或者分区表更新完但文件系统没resize的情况。排查思路很简单:
lsblk # 磁盘大小和分区大小是否一致 df -h # 文件系统实际可用空间 sudo partprobe # 重新读取分区表如果lsblk中sda总大小已经变大但分区大小没变,说明新增空间还在末尾空闲着,需要growpart或者fdisk新建分区来占用它。如果分区大小已经变大但df -h没变,说明文件系统还是老样子,对ext4需要执行resize2fs。
还有一类情况比较隐蔽:你的根分区用了LVM,而逻辑卷大小没跟着变。这时候用lvs先看一下逻辑卷大小,再用lvextend扩容逻辑卷,最后resize2fs。很多人挂在“分区分了但忘了扩逻辑卷”这一环,lvs一眼就能看出来。
我把这个排查思路整理成了速查表,方便按图索骥:
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
| lsblk总大小变小(未变) | VMware层没扩展成功 | 关机后重新执行扩展 |
| 总大小变大但分区大小没变 | 分区表没更新或没建新分区 | partprobe后growpart/fdisk |
| 分区大小变大但df不变 | 文件系统没resize | resize2fs(ext4) |
| LVM下分区变大但df不变 | 逻辑卷没扩展 | lvextend + resize2fs |
| 挂载后重启不生效 | fstab没写或写错 | 检查fstab UUID后mount -a |
5.3 不同场景的方案选择建议
说到底,磁盘扩容并没有一个“唯一正确答案”,完全取决于你的使用场景:
- 数据盘挂载到独立目录:适合新增分区+格式化+fstab的方案,好处是系统盘和数据盘分离,重装系统时数据盘不受影响。
- 合并进根分区:适合根分区紧张但又不想动分区结构的场景,整个操作可以在线完成,不用重启,很爽。
- 运行数据库服务:建议用LVM方案,或者直接在虚拟磁盘层面多划一个卷组,后期弹性更大,不用来回动分区表。
- 测试环境的日常备份:如果是用来验证软件或练手,建议直接在扩容完成后做一次干净快照,后续坏了随时回滚。
我个人在实际操作中的体会是,如果条件允许,优先用LVM来做数据盘规划,这样后续扩容简直就是改个参数的事。这次是因为虚拟机当初没有规划LVM数据盘,只能用传统分区方式补课,好在也顺利解决了。
最后再分享一个细节:扩容完成后,记得重新生成一下虚拟机的备份或快照,把这台已经稳定的环境固下来,以后再有新需求就不用从头再来。还有个小技巧,扩展完根分区后可以顺手清理一下apt缓存和journal日志,通常能腾出好几个G,有时候都不用扩容了。