在 VPS 控制台把云盘从 40 GB 扩到 80 GB,登录后 df -h 仍显示 40 GB,是常见的“扩容成功但系统没空间”问题。原因通常是虚拟磁盘、分区、LVM 和文件系统只扩了前面一层。本文针对 Ubuntu VPS 上的 ext4、XFS 和常见 LVM 根分区,教你先判断卡在哪一层,再执行对应命令,并验证新增空间真的能被网站或容器使用。
扩容流程通常是:服务商把云盘变大 → 客户机看见更大的块设备 → 分区变大 → 文件系统变大。如果根分区用了 LVM,还多出 PV(物理卷)→ VG(卷组)→ LV(逻辑卷) 三层。Ubuntu LVM 文档解释了这几个层次;直接对错误设备运行 resize2fs,既解决不了容量问题,也可能误操作其他盘。
先确认控制台里是扩大原云盘,还是新加了一块数据盘。新加的磁盘不会自动让 / 变大;本文的根分区示例不能套在新盘上。然后在 VPS 执行只读检查:
findmnt -no SOURCE,FSTYPE,TARGET /
df -hT /
lsblk -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINTS,PKNAME
sudo pvs
sudo vgs
sudo lvs
如果 pvs、vgs、lvs 提示命令不存在,且 findmnt 指向普通 /dev/vda1、/dev/nvme0n1p1 等分区,站点多半没有使用 LVM,不需要为了扩容再安装或创建 LVM。以 lsblk 显示磁盘 80 GB、根分区 40 GB、df -hT / 显示 ext4 40 GB 为例,分区和文件系统都还没扩;如果分区已是 80 GB、df 仍是 40 GB,只需扩文件系统。
findmnt/lsblk 所见 | 下一步 |
|---|---|
| 磁盘仍是旧容量 | 返回服务商控制台确认扩容已完成;必要时按服务商说明重扫设备或重启 |
| 磁盘变大、普通分区没变 | 确认目标分区后,用 growpart 扩分区 |
| 分区变大、ext4/XFS 文件系统没变 | 对正确设备执行 resize2fs,或对 XFS 挂载点执行 xfs_growfs |
根文件系统在 /dev/mapper/...,VG 没有空闲空间 | 先扩承载 PV 的分区,再 pvresize、扩 LV |
| VG 已有空闲空间、LV 较小 | 不必再 growpart;直接决定给哪个 LV 分配空间 |
growpart 只能把指定分区扩到后续空闲空间或下一个分区之前;如果目标分区后面还有别的分区挡住,不能靠盲目重复命令解决。Ubuntu 的 growpart 手册提供 -N 预演模式,正式修改前应先看它要改哪一个分区。
扩分区与文件系统会改写存储元数据。先在服务商控制台创建该盘快照,记下快照 ID、时间、是否包含数据盘,以及恢复方式;数据库另做一致性导出,重要文件再复制到另一台机器或对象存储。运行中的数据库和文件系统快照可能不处于同一业务时刻,有订单、支付或上传写入时要选择维护窗口,必要时暂停写入。站内的快照与备份区别和备份恢复演练可用来检查回退准备。
确认 SSH 与服务商救援控制台都能进入机器。目标磁盘若已经 100% 满,growpart 创建临时文件也可能失败;先定位占用并留出少量工作空间,不要在不明用途的目录执行通配删除。Ubuntu 或 Debian 可用 sudo apt install cloud-guest-utils 安装 growpart;XFS 需要 xfsprogs。下面每组命令互斥,只按自己的布局选一组,并替换设备名。
假设只读检查确认:整盘是 /dev/vda,根分区是 /dev/vda1,文件系统是 ext4,且 vda1 后面有可用空间。先预演并阅读输出;-N 在“已无可扩空间”时可能返回非零,先回到 lsblk 判断原因。
sudo growpart -N /dev/vda 1
sudo growpart /dev/vda 1
lsblk -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINTS
sudo resize2fs /dev/vda1
df -hT /
注意 growpart /dev/vda 1 中的空格:前一个参数是整盘,后一个是分区编号。在 NVMe 设备上,根分区若实际是 /dev/nvme0n1p1,对应命令应是 growpart /dev/nvme0n1 1,文件系统设备则用 /dev/nvme0n1p1。官方云盘扩容文档也按“检查磁盘 → 扩分区 → 扩文件系统”这个顺序处理。不能仅凭示例设备名猜自己的根分区。
如果 lsblk 已显示分区占满整盘,只是 df 还没变,则跳过 growpart,只运行对该 ext4 设备的 resize2fs。如果根文件系统直接建立在整个 /dev/vdb 上,没有分区表,也不要运行 growpart;确认设备与文件系统类型后,直接扩对应文件系统。
假设根分区是 /dev/nvme0n1p1,整盘 /dev/nvme0n1 已扩大,findmnt 显示根文件系统是 XFS。先扩分区,再对挂载点 / 扩 XFS;xfs_growfs 接收挂载点,不是分区号。
sudo growpart -N /dev/nvme0n1 1
sudo growpart /dev/nvme0n1 1
lsblk -o NAME,PATH,SIZE,TYPE,FSTYPE,MOUNTPOINTS
sudo xfs_growfs /
df -hT /
如果 XFS 挂在 /data,最后一条扩容命令要写 sudo xfs_growfs /data。若分区已扩过,只需执行 xfs_growfs。XFS 不支持像某些文件系统那样原地缩小;扩容前尤其要确认盘和挂载点,回退靠快照或备份恢复。
下面是假设布局:/dev/vda 是云盘、/dev/vda3 是 LVM 的 PV、根目录在 /dev/ubuntu-vg/ubuntu-lv。你的 PV 可能不是第 3 分区,LV 名也可能不同;先用 pvs、vgs、lvs 和 findmnt 对照确认。若 vgs 已有足够的 VFree,可以直接跳到扩 LV;若 PV 所在分区未变大,先扩它。
sudo growpart -N /dev/vda 3
sudo growpart /dev/vda 3
sudo pvresize /dev/vda3
sudo pvs
sudo vgs
然后按业务需要分配 VG 剩余空间。例如只给根 LV 增加 20 GB,并让 LVM 尝试同步扩展受支持的文件系统:
sudo lvextend --resizefs --size +20G /dev/ubuntu-vg/ubuntu-lv
sudo lvs
df -hT /
--resizefs 的行为见Ubuntu LVM 管理文档;增量大小不得超过 VFree。如确实要把 VG 的全部剩余空间给这个 LV,可在确认其他 LV 不需要保留空间后,改为 sudo lvextend -l +100%FREE -r /dev/ubuntu-vg/ubuntu-lv。如果 PV 直接建在整盘而不是分区上,不应使用 growpart,而是确认整盘容量后对那个 PV 运行 pvresize。LUKS 加密、RAID、LVM thin pool 和跨盘 VG 的布局更复杂,先按各层的实际拓扑制定方案,不套用上述示例。
扩容后同时查看 lsblk 和 df -hT:前者确认块设备、分区与 LV 大小,后者确认挂载点文件系统可用容量。再在目标目录做一次非破坏性的写入测试,检查网站、数据库和容器日志;不要把备份放在刚扩大的同一块盘上当作唯一恢复手段。
| 报错或现象 | 先检查 |
|---|---|
growpart: NOCHANGE | 云盘是否真变大、目标分区是否已到末尾、后面是否还有其他分区 |
growpart 提示无法创建临时目录 | 根文件系统或 /tmp 是否完全满;先安全释放少量空间 |
resize2fs: Bad magic number | 目标是否其实是 XFS、LVM PV 或写错设备名;用 findmnt、lsblk -f 重查 |
xfs_growfs: not a mounted XFS filesystem | 给的是设备名还是挂载点、文件系统是不是 XFS |
pvresize 后 VFree 仍是 0 | PV 所在分区是否已扩大、内核是否已识别新分区表、PV 是否选错 |
df 不变但 lsblk 已变大 | 还差文件系统扩容,或查看了错误的挂载点 |
若修改分区表后内核仍显示旧大小,先保留快照并按服务商指引安排重启,再重新检查 lsblk;不要连续重写分区表。出现 I/O 错误、分区布局不符合预期或文件系统报损坏时,停止写入,使用救援控制台与快照排查。恢复旧快照会丢失快照之后的新写入,需要先保全新数据。也不要为了“恢复原价”在系统内直接缩小文件系统或分区:云盘能否缩容、如何计费要看服务商,通常需要建新盘迁移。
控制台扩容后必须重启 VPS 吗? 不一定。有些平台和镜像能在线识别并扩展,另一些布局需要重扫或重启。先看 lsblk 与 df -hT,再按平台说明处理。
为什么 df -h 和 lsblk 大小不同? lsblk 看块设备与分区,df 看已挂载文件系统。只扩云盘或分区时,df 不会自动反映新容量。
Docker 占满空间,扩根盘还是数据盘? 先用 docker system df 和 df -hT /var/lib/docker 确认 Docker 实际存储落在哪个挂载点;只扩根盘不一定能救挂在独立数据盘上的 Docker 目录。
