如果你手头那台 Linux 服务器或者家用 NAS 的根目录 / 又满了,或者 /home 空间不太够,这篇文章应该能帮你少走不少弯路。我这次是 20231008 的一次真实操作记录,处理的是“/home 和根目录扩容”的问题,前后折腾了小半天,所幸顺利搞定。本文会把 LVM 和非 LVM 两条路线都讲清楚,还包括 VMware 虚拟机里 vmdk 扩容后的完整操作链路,适合 Linux 运维、自建 NAS 玩家,以及那些第一次接手生产服务器但又不敢乱动分区的朋友。
1. 扩容前必须搞清楚的3件事
很多新手一看到 df -h 里 / 或者 /home 使用率达到 100%,第一反应就是去找新硬盘或者直接删文件。其实在动手扩容之前,有三个问题必须先确认清楚,否则操作到一半很可能遇到“没法在线扩容”“文件系统不支持缩容”“重启后找不到分区”这种坑。
1.1 先判断文件系统格式和分区结构
扩容方式完全取决于你的磁盘是怎么分区的、文件系统是哪种格式。同一台机器上,/ 和 /home 可能分别隶属于独立分区,也可能都挂在同一个卷组下面,甚至 /home 可能只是根目录里的一个普通目录而不是独立分区。所以第一步就是用命令把“家底”翻出来:
df -hT lsblk blkid pvs vgs lvsdf -hT 能直观看到文件系统类型和挂载点,比如 ext4、xfs、btrfs。lsblk 可以看分区的树形结构,能区分出 sda1、sda2 这些是物理分区,还是 lvm 逻辑卷。blkid 则能显示每个分区和逻辑卷的 UUID 和类型。
如果 pvs、vgs、lvs 能输出内容,说明系统在用 LVM 管理磁盘;如果提示 command not found,那就是传统分区或者云镜像的默认分区。这一步决定后续能不能直接在系统里热扩容。举个例子,我这次处理的机器就是 /dev/sda2 挂在 /,/dev/sda3 挂在 /home,两个分区都属于同一个卷组 vg_root,那就简单多了,直接 lvextend 就能搞定。
1.2 判断能不能在线扩容
知道是不是 LVM 之后,还要清楚“在线扩容”的边界:
- LVM 的逻辑卷 LV 可以在系统运行状态下扩展,甚至可以在线缩小(ext4 可以,xfs 不行)。
- 传统分区(非 LVM)如果要扩展根分区,因为根分区始终处于挂载状态,不能直接修改分区表,必须借助 live CD 之类的离线环境。
- ext4 文件系统支持在线扩大,也支持缩容时需要离线并先缩小文件系统;xfs 只支持扩大,不支持缩小。
- 如果你的根分区不是 LVM,而是云服务器那种 vda1 直接挂载,很多云厂商的“一键扩容”功能会自动处理分区表,但自建物理机没有这个便利。
所以先别急着下载工具,先跑一遍 1.1 的命令,把类型确定下来,再决定走哪条路线。我见过有人在一台 btrfs 上用 resize2fs,结果直接报错,因为 btrfs 要用 btrfs filesystem resize,完全不是一套东西。
1.3 备份和数据安全优先
扩容操作的失败率不高,但一旦失败,丢数据的代价极高。尤其是缩容 /home 或者用 GParted 调整分区边界时,中间任何一步断电、死机都可能导致分区表错乱。所以操作之前一定要备份。
最稳妥的方式是把整个系统做成虚拟机快照(如果是虚拟机),或者用 dd 备份关键分区。考虑到根分区通常比较大,全量 dd 不一定现实,至少要把 /home 里不可再生的数据,比如数据库文件、容器 volume、个人文档,拷贝到外部存储或者另一块磁盘上。
我自己的习惯是操作前执行一次:
rsync -av /home/ /mnt/backup/home/然后把 /etc/fstab、分区表信息也导出来:
fdisk -l > partition.txt cat /etc/fstab这些记录能在事故发生后帮你快速恢复现场。别嫌麻烦,这个动作能省掉 99% 的后续风险。
2. 基于LVM的扩容实操(CentOS/RHEL主流方案)
如果你的系统是 CentOS、RHEL、Rocky Linux,并且安装时默认用了 LVM,那扩容其实非常顺滑。整体思路是:新磁盘或者未分配空间 → 创建物理卷 PV → 扩展到卷组 VG → 再扩展逻辑卷 LV → 最后刷新文件系统。
2.1 添加新磁盘并创建PV
假设原卷组 vg_root 已经没有空闲空间了,而系统里新识别了一块 100G 的磁盘 /dev/sdb。先确认一下:
lsblk如果能看到 /dev/sdb 但没有分区,就可以直接把它做成物理卷:
pvcreate /dev/sdb vgextend vg_root /dev/sdb这里有个细节:很多人习惯先用 fdisk 给新盘建立分区再 pvcreate,其实如果把整个盘给 LVM 用,直接 pvcreate /dev/sdb 也不会有问题。但如果你后面还要维护这块盘,或者想更规范一点,建议还是用 fdisk 建一个分区,并把分区类型改成 8e:
fdisk /dev/sdb依次输入 n 新建分区、p 主分区、回车选默认分区号、再回车选起始扇区、回车选结束扇区,最后 t 改类型为 8e,w 保存。然后再 pvcreate /dev/sdb1。
建完之后用 pvs 确认新的 PV 已经出现,再用 vgs 查看卷组的空闲空间。如果显示 VFree 100G,说明 VG 已经扩展成功。
2.2 扩展VG和LV
接下来就要决定把这 100G 给哪个逻辑卷了。先看一下现有逻辑卷列表:
lvs通常会有类似这样的输出:
lv_root vg_root -wi-ao---- 50G lv_home vg_root -wi-ao---- 200G如果这次需要给根目录扩 80G,给 /home 扩 20G,可以这样:
lvextend -L +80G /dev/vg_root/lv_root lvextend -L +20G /dev/vg_root/lv_home注意这里的 -L +80G 是“增加 80G”,如果是 -L 80G 就是“扩展到 80G”。一字之差,含义完全不一样,实际操作时最好再 lvs 确认一下。
扩展完 LV 之后,还差最后一步:刷新文件系统。很多新手在这一步翻车,因为 lvextend 只改变了逻辑卷大小,文件系统还停留在原来的尺寸,df -h 不会立刻看到变化。
2.3 刷新文件系统(ext4/xfs区别处理)
文件系统刷新命令取决于你的类型。如果是 ext4:
resize2fs /dev/vg_root/lv_root resize2fs /dev/vg_root/lv_home如果是 xfs:
xfs_growfs / xfs_growfs /home注意 xfs 的刷新命令后面跟的是“挂载点”,而不是逻辑卷设备路径。命令执行后,用 df -hT 验证:
df -hT看到 / 和 /home 的空间增加,就说明扩容成功了。
这里为什么要区分 ext4 和 xfs?因为 ext4 可以支持缩小,也就是说你将来可以先把 /home 缩小,再把空间挪给 / 这种操作。但 xfs 只能扩大不能缩小,如果你当初 /home 用了 xfs,想缩它是没门的,只能备份数据、删除逻辑卷、重建再恢复数据。这一点在选择文件系统时就要考虑好。
3. 非LVM分区如何扩容(Ubuntu/纯分区方案)
很多 Ubuntu 桌面版、windows+linux 双系统或者一些云主机镜像,用的不是 LVM,而是传统分区。比如 /dev/sda2 直接挂载 /,/dev/sda3 挂载 /home。这种情况想扩大根分区就麻烦一些,因为根分区在系统运行中无法卸载,不能直接改分区表。最靠谱的就是做一张 GParted Live 启动盘,离线调整分区。
3.1 GParted Live的烧录与启动
GParted 是目前调整分区最好用的工具之一,它同时支持 ext4、xfs、btrfs、ntfs 等多种文件系统的移动和缩放操作。第一步是下载 GParted Live 的 ISO 镜像,然后用 rufus(Windows)或者 dd 命令(Linux)写入 U 盘。
在 Linux 里写 U 盘时注意不要写错设备:
dd if=gparted-live-xxx.iso of=/dev/sdX bs=4M status=progress sync然后重启电脑,从 U 盘启动。如果没进入 GParted,而进到了原系统,检查 BIOS 里的启动顺序,或者临时按 F12、Esc 选择启动介质。
进入 GParted Live 后,如果默认是英文界面,可以在启动菜单选择键盘布局和语言。图形界面起来后会直接显示所有磁盘和分区。
3.2 调整分区流程与注意事项
假设当前磁盘布局是 /dev/sda2 挂载 /,/dev/sda3 挂载 /home,sda2 前面或者后面有未分配空间,那就直接选中 sda2,右键 Resize/Move,把右边的箭头拉到最大,然后 Apply。如果空间在 /home 附近,而你想扩充根分区,那就需要先缩小 /home,再扩大根分区。
但这里有一个大坑:如果 /home 是独立分区,GParted 想要缩小它,分区必须处于卸载状态。在 GParted Live 里,由于根分区已经是未挂载状态,/home 一般也不会自动挂载,所以条件通常可以满足。但一旦 /home 的分区有数据正在被系统占用,或者 swap 分区挂载了,操作会被拒绝。
调整时要注意“对齐到 MiB”。GParted 默认启用对齐,不要取消它,否则新分区边界可能没有按柱面对齐,导致性能变差甚至无法启动。
全部操作完成后,退出 GParted Live,重启进入系统,df -hT 就能看到变化。这里面的关键点就是:传统分区根目录扩容,必须离线操作,不能在系统里直接完成。
3.3 在线扩容根分区的约束
有人会问,我在云服务器上扩容根分区,好像不用启动盘啊?对,云厂商通常通过底层卷扩容和 virtio 驱动配合,在线把磁盘大小变大,然后再用 growpart 扩展分区,resize2fs 扩展文件系统。但这属于云环境的特殊机制,物理机和传统虚拟机里根分区不能这样搞。
在物理机上,即便是加了新硬盘,想把新硬盘的空间合并到已有的 sda 分区,也做不到,因为传统分区的边界是固定的。GParted 能做到的,只是移动和改变同一块物理磁盘上的分区边界,并不能跨磁盘合并。
所以如果你有一块新硬盘想给非 LVM 系统的根目录扩容,现实一点的方案是把新盘挂到某个目录,然后把数据挪过去,或者干脆重装系统时用 LVM。这也是为什么我更推荐在生产环境用 LVM 的核心理由。
4. 虚拟机扩容场景:vmdk/磁盘扩容后的完整链路
现在很多自建服务器都是虚拟机跑出来的,VMware、Proxmox、VirtualBox 都有各自的虚拟磁盘格式。扩容前如果只改虚拟机设置,里面看不到新空间;如果直接改客户机分区,又会把虚拟磁盘文件搞坏。这里我用 vmdk 举例,把完整链路走一遍。
4.1 宿主机层磁盘扩容
在 VMware 中,先关机虚拟机(强制要求,尤其是有快照的情况下)。然后右键虚拟机 → 编辑设置 → 硬盘 → 工具 → 扩展,把磁盘大小从 100G 改成 200G。如果虚拟机有快照,扩展按钮是灰色的,必须先删除或用快照创建新分支,否则无法扩展。
VirtualBox 也类似:设置 → 存储 → 选中虚拟硬盘 → 属性 → 调整大小。
宿主机层扩容完成后,新空间对客户机来说还是“未分区”的空白空间。如果你用 lsblk 看,会看到 /dev/sda 的容量变大了,但 sda1、sda2、sda3 这些分区的大小没变,sda 末尾多了空闲空间。
4.2 fdisk新建分区与PV/VG/LV扩展
如果客户机是 LVM 系统,就可以把新增的空白空间变成一个新分区,然后加入 LVM。先在客户机里看磁盘:
lsblk比如原来 /dev/sda1 → /boot,/dev/sda2 → LVM 的 PV,/dev/sda3 → 其他分区。现在磁盘多了 100G,可以用 fdisk 在空闲空间新建一个分区:
fdisk /dev/sda输入 n,选择分区号(通常选 4),起始扇区直接回车,结束扇区回车,t 修改分区类型为 8e,w 保存。
然后让内核重新读取分区表:
partprobe /dev/sda如果分区表一直被占用,也可以先 lsblk 确认,或者用 partx -a /dev/sda 刷新。然后把新分区变成 PV:
pvcreate /dev/sda4 vgextend vg_root /dev/sda4接下来和 2.2、2.3 一样,lvextend + resize。
4.3 /home和/根目录同时扩容的思路
有时候根本不需要新磁盘,而是 /home 分多了,/ 不够用。如果整个系统是 LVM,且 / 和 /home 是两个独立的 LV,同时同一个 VG,那么完全可以把 /home 缩下来,把空间补给根目录。
但前提是 /home 的文件系统必须是 ext4,xfs 不能缩。流程如下:
先备份 /home 数据,然后卸载 /home:
umount /home检查文件系统:
e2fsck -f /dev/vg_root/lv_home把文件系统从 200G 缩到 180G:
resize2fs /dev/vg_root/lv_home 180G再把逻辑卷本身也缩到 180G:
lvreduce -L 180G /dev/vg_root/lv_home注意顺序不能反,必须先缩小文件系统,再缩小 LV。如果先 lvreduce 再 resize2fs,文件系统认为后面的块不见了,大概率丢数据。
释放出来的 20G 就留在卷组里,可以扩展根目录:
lvextend -L +20G /dev/vg_root/lv_root resize2fs /dev/vg_root/lv_root最后重新挂载 /home,恢复数据:
mount /home rsync -av /mnt/backup/home/ /home/这样根目录和 /home 都得到了扩容,整个链路清晰且不会丢数据。这里面最考验人的是操作顺序和耐心,尤其在 umount /home 之后,任何中断都可能导致数据无法访问,所以开机时尽量用 tmux 或者 screen 跑这些命令,防止终端断线。
5. 常见问题与排查技巧
就算流程看得再明白,实际操作中还是会遇到各种“意外”。我把这次以及之前几次扩容踩过的坑整理成了一张速查表,另外也分享几个自己的避坑心得。
5.1 典型问题速查表
下面这些都是我真实遇到的问题,不是无端猜测:
| 故障现象 | 可能原因 | 解决办法 |
|---|---|---|
| df -h 显示还是原来的大小 | 扩完 LV 没有执行 resize2fs 或 xfs_growfs | 检查文件系统类型,执行对应刷新命令 |
| resize2fs 报错 Bad magic number in super-block | 文件系统不是 ext4,而是 xfs 或 btrfs | 不要用 resize2fs,xfs 用 xfs_growfs,btrfs 用 btrfs filesystem resize |
| xfs_growfs 报 Is a directory | 参数写成了设备路径 | xfs_growfs 后面跟挂载点,比如 xfs_growfs / |
| 虚拟机硬盘扩展后 lsblk 看不到新容量 | 客户机没有重新识别磁盘 | 重启虚拟机,或触发在线重新扫描(如 echo 1 > /sys/class/scsi_device/.../device/rescan) |
| fdisk 新建分区后保存正常,partprobe 还是看不到分区 | 分区表被系统缓存占用 | 大多数情况重启最省事,也可以尝试 partx -a /dev/sda |
| PV 状态显示 unknown device | 底层磁盘或分区发生变更 | vgreduce --removemissing --force 移除丢失 PV 后再重新添加 |
| lvreduce 后数据无法访问 | 先缩小了 LV,后缩小文件系统 | 立刻停止一切写入,使用 e2fsck 尝试修复,下一次先缩文件系统再缩 LV |
| 扩容后 / 挂载异常,无法启动 | 调整分区导致 UUID 变了 | 尽量别动原有分区起点;若变了,在 live 环境改 /etc/fstab 的 UUID |
5.2 我的避坑心得与建议
这次 20231008 的操作让我印象最深的几点,单独拿出来说下:
第一,扩容之前一定要确认根目录和 /home 到底是不是同一个卷组。如果是同一个卷组,调整起来非常灵活;如果根本不在一块磁盘上,那思路就完全不同了。用 vgs 看一下就明白。
第二,尽量用 tmux 或 screen。我习惯在远程服务器上操作时先把会话开成 tmux,即使 SSH 断线,命令也能继续跑完,不会出现扩容到一半卡住的尴尬。
第三,别盲目追求最新工具。CentOS 7 上旧版 resize2fs 对超大分区性能很差,但也没有必要为了扩容去升级内核。只要顺序对,就够用。
第四,如果你的 /home 用的 xfs,建议别再想“缩 home 扩根”的操作了,xfs 不支持缩容,唯一办法就是全新备份、删除 LV、重建成 ext4 再恢复数据,过程繁琐且风险高。所以新装系统时,如果不是特别需要 xfs 的特性,用 ext4 会多一条“后悔药”。当然,xfs 的稳定性在大并发写入场景确实有优势,选型时要自己权衡。
最后再分享一个小技巧:扩容后不同目录的空间变化,有时候 df 显示不对,是因为文件系统有延迟,等一两分钟再刷新。另外 lvextend 支持 -r 参数,像这样:
lvextend -r -L +20G /dev/vg_root/lv_root它会在扩展逻辑卷之后自动调用 resize2fs 或者 xfs_growfs,一步到位。但这个自动行为只在部分发行版上可用,老系统还是手动执行更稳妥。我更建议手动来,每跑一步都确认一次,心里有底。
这次扩容最终把根目录从 50G 扩到了 130G,/home 也从 200G 扩到了 220G,整个过程没有重启生产服务,算是比较顺的一次。希望这篇记录也能帮你把 /home 和根目录的空间理顺,别再被“磁盘满了”追着跑。