云服务器把云盘从 40G 调到 100G,重启后 df -h 里根分区还是 40G;或者 Ubuntu Server 装完发现卷组里空着一大截、根分区只用了其中一部分。这类问题的共同点是:底下那层变大了,上面那层没跟着长。磁盘、分区、LVM、文件系统是四层,哪一层没长,处理命令完全不同。下面先给排查顺序,再分场景处理。
一、先定位:到底哪一层没长
四条命令基本能看清全貌:
df -hT # 文件系统层:挂载点、类型、容量、使用率
lsblk -f # 块设备树:磁盘 → 分区 → 文件系统,一眼看出谁没长
sudo fdisk -l /dev/vda # 磁盘总容量 vs 分区结束扇区
sudo parted /dev/vda print free # 分区表里还有没有 Free Space,在开头、中间还是末尾
findmnt / # 根分区到底挂在哪个设备上如果用的是 LVM(Ubuntu Server 默认安装、云镜像的 LVM 变体都是),再加三条:
sudo pvs # 物理卷:PV 认识多大空间
sudo vgs # 卷组:还剩多少没分配(VFree)
sudo lvs -o +lv_size,vg_free # 逻辑卷:LV 实际分了多大对照现象找对应章节:
| 现象 | 说明 | 处理 |
|---|---|---|
lsblk 里磁盘 100G,分区仍是 40G | 分区没扩 | 场景二:growpart |
分区已是 100G,df 还是 40G | 文件系统或 LVM 没扩 | 场景二 / 场景三 |
vgs 里 VFree 还有几十 G | 卷组空间没分给 LV | 场景三:lvextend |
lsblk 里有整块盘没有挂载点 | 空闲的新盘 | 场景一:分区挂载 |
parted print free 显示空闲块在分区之间 | 末尾以外的空间不能直接扩 | 场景四 |
二、场景一:整块盘还没挂载(新增数据盘)
云厂商挂了一块数据盘、或者机器上加了一块硬盘,需要分区、格式化、挂载并写进 /etc/fstab:
# 1. 认盘:确认要操作的是 sdb,别把系统盘写坏
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
# 2. 建分区表并分一个区(GPT,对齐到 1MiB)
sudo parted -s -a optimal /dev/sdb mklabel gpt
sudo parted -s -a optimal /dev/sdb mkpart primary ext4 0% 100%
# 3. 格式化
sudo mkfs.ext4 -L data /dev/sdb1
# 4. 挂载
sudo mkdir -p /data
sudo mount /dev/sdb1 /data
df -hT /data
# 5. 取 UUID 并写 fstab(不要写 /dev/sdb1)
sudo blkid /dev/sdb1
echo 'UUID=替换成上一步的输出 /data ext4 defaults,nofail,x-systemd.device-timeout=10 0 2' | sudo tee -a /etc/fstab
# 6. 关键:校验 fstab 写得对不对,别等重启才发现
sudo mount -a
findmnt /data几个必须知道的点:
- 用 UUID 而不是
/dev/sdb1:设备名顺序会随磁盘增减、控制器变化而变,重启后可能挂错盘,甚至卡在启动阶段。 nofail:这块盘没挂上时不阻塞系统启动;x-systemd.device-timeout=10顺手限制等待时间,避免开机卡几十秒。mount -a一定要执行:fstab 写错重启后会掉进 emergency mode,先跑一遍就能当场发现。- 挂载会遮住原目录内容:
/data里原本有文件的话,挂载后看不到(数据没丢,但会被隐藏),先挪走或清空。 - 数据盘也可以不分区,直接
mkfs.ext4 /dev/sdb格式化整盘。分区的好处是以后便于拆分、也方便一些工具识别;习惯上还是分一个区。 - 大文件、大目录为主的场景可以用 XFS:
sudo mkfs.xfs /dev/sdb1,fstab 里的类型相应写xfs。
三、场景二:磁盘变大了,分区没扩
在云控制台把云盘扩容,或在 VMware / VirtualBox 里扩了虚拟磁盘,操作系统里看到磁盘总量变大,但分区表还是旧的。用 growpart 扩最后一个分区(它来自 cloud-guest-utils,Ubuntu 默认已装,缺了就 sudo apt install cloud-guest-utils):
lsblk
# 例如:vda 100G,但 vda3 还是 40G
# 扩最后一个分区,分区号按 lsblk 里的实际编号填
sudo growpart /dev/vda 3
lsblk # 确认 vda3 已经变成 100G 左右分区本身变大并不会让文件系统跟着变大,还要再扩一层:
# ext4:支持挂载状态下在线扩容,不用卸载
sudo resize2fs /dev/vda3
# xfs:只能扩不能缩,参数给挂载点而不是设备
sudo xfs_growfs /如果这个分区下面是 LVM 的 PV,别停在这里,继续看场景三。
顺带一提:Ubuntu 云镜像上 cloud-init 会在开机时自动跑 growpart 和 resizefs,多数情况下重启一次就好了。可以确认它有没有生效,或者手动触发一次:
cloud-init status --long
sudo cloud-init single --name cc_growpart
sudo cloud-init single --name cc_resizefs这一步常见的几种报错:
NOCHANGE: partition 3 is size ..., it cannot be grown:分区已经贴到磁盘末尾了,问题不在分区层,往上找文件系统或 LVM。WARNING: the kernel failed to re-read the partition table:内核没重新读分区表,sudo partprobe /dev/vda或重启一次即可。- 提示 GPT 备份头不在磁盘末尾(磁盘变长后原备份头位置过期):
sudo sgdisk -e /dev/vda重建备份 GPT(需要gdisk包),parted交互模式遇到同样提示选 Fix 也行。 resize2fs: The filesystem is already N blocks long. Nothing to do!:分区没扩成功,回上一步检查growpart的输出。
四、场景三:LVM 有剩余空间,根分区没用满
Ubuntu Server 默认安装的布局通常是 /dev/vda3 做 PV,卷组 ubuntu-vg,里面 ubuntu-lv 挂根分区。安装时只占卷组一部分、或者扩盘后只做了 growpart 没做 pvresize,都会出现「卷组里空着几十 G,根分区还是满的」。
# 1. 先看卷组还剩多少
sudo vgs
sudo lvs -o +lv_size,vg_free
# 2. 让卷组认识新增的物理空间(growpart 之后必须先做这步)
sudo pvresize /dev/vda3
# 3. 扩 LV 并顺手扩文件系统:-r 等价于 --resizefs
sudo lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv说明:
-l +100%FREE表示把卷组剩余空间全部给它;只想给固定大小用-L +20G。-r会调用fsadm,自动判断该用resize2fs还是xfs_growfs,比只扩 LV 却不动文件系统稳得多。- 等价的两步写法:
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv之后sudo resize2fs /dev/ubuntu-vg/ubuntu-lv。只做前者的话df不会有任何变化。 - 根分区在线扩容对 ext4 / XFS 都是安全的,不需要卸载、不需要重启;反过来缩容必须卸载,ext4 能缩、XFS 不能缩,做之前务必备份。
- 想确认是不是有快照占着卷组空间:
sudo lvs -a -o +segtype,devices。
五、场景四:空闲空间不在分区末尾
parted print free 显示 Free Space 夹在两个分区中间时,末尾以外的空间没法用 growpart 直接吃进来。三个选择,按风险从低到高:
- 单独划一个分区挂到
/data:最省事、风险最低,等于把空闲空间当第二块盘用(流程见场景一)。 - 并入 LVM:把空闲空间做成新分区 →
pvcreate→vgextend ubuntu-vg /dev/vda4→lvextend -r,之后根分区可以按需扩,灵活度最高。 - 合并进根分区:需要移动分区,属于离线操作。备份 → 用 GParted Live 之类的启动盘移动分区 → 再扩文件系统。耗时长、有风险,生产环境不建议在线做。
六、扩完之后的验证与收尾
df -hT
lsblk -f
sudo vgs; sudo lvs
sudo findmnt /data
# 纯数据盘可以把 ext4 的 root 保留块从 5% 调到 1%,让可用空间更接近容量
sudo tune2fs -m 1 /dev/sdb1- 新挂的盘必须确认
sudo mount -a无输出、findmnt能看到,再考虑重启。 - 云盘扩容记得确认计费方式变化,虚拟机扩容前最好先打一个快照,出问题能回滚。
- 扩容是「从下往上」逐层做:磁盘 → 分区 → PV → LV → 文件系统,跳过任何一层,
df都不会变。
七、速查卡
# 定位:哪一层没长
df -hT && lsblk -f && sudo parted /dev/vda print free && sudo vgs
# ① 新盘挂载(分区 → 格式化 → UUID 写 fstab → mount -a 验证)
sudo parted -s -a optimal /dev/sdb mklabel gpt
sudo parted -s -a optimal /dev/sdb mkpart primary ext4 0% 100%
sudo mkfs.ext4 /dev/sdb1 && sudo mkdir -p /data && sudo mount /dev/sdb1 /data
sudo blkid /dev/sdb1
echo 'UUID=xxx /data ext4 defaults,nofail 0 2' | sudo tee -a /etc/fstab
sudo mount -a
# ② 分区扩容(磁盘已变大)
sudo growpart /dev/vda 3
sudo resize2fs /dev/vda3 # ext4;XFS 用 sudo xfs_growfs /
# ③ LVM 扩容
sudo pvresize /dev/vda3
sudo lvextend -r -l +100%FREE /dev/ubuntu-vg/ubuntu-lv一句话总结:先用 lsblk -f 加 parted print free 分清是分区、LVM 还是文件系统没长,再按 growpart → pvresize → lvextend → resize2fs(XFS 用 xfs_growfs)从下往上逐层扩;新盘则走「分区 → 格式化 → UUID 写 fstab → mount -a 验证」这套流程。
评论区