刚接手一台Ubuntu服务器,同事说“开机黑屏,系统挂了”。我第一反应不是查显卡,而是先看了一眼磁盘——果然,df -h里根分区直接100%。这个词我太熟了:Ubuntu磁盘空间不足导致的黑屏无法启动,在物理机和虚拟机上都出现过。很多朋友遇到黑屏就先怀疑驱动、怀疑内核、甚至重装系统,但其实大半情况下,问题根本不复杂,就是根分区或者/boot被塞满了,系统在启动过程中起不来关键服务,最后屏幕就黑了。
这篇文章我打算把整条处理链路完整写一遍:先从启动链路讲清楚“磁盘满为什么会导致黑屏”,再给出一套在纯命令行里紧急腾挪空间的命令组合,然后重点演示磁盘容量扩展的两种主流方式(LVM在线扩容和非LVM分区扩容),最后把扩容过程中遇到的坑和排查思路整理成一个速查表。不管是自己用的Ubuntu工作站,还是公司里的服务器,这套流程基本都能直接套用。
1. 磁盘满了为什么会让Ubuntu直接黑屏
1.1 黑屏不是显卡的锅,先看启动链路
很多人的第一反应是“图形界面坏了,重装驱动”,但我见过的绝大多数“黑屏无法启动”,其实发生在显示管理器还没拉起来之前。
Ubuntu的启动链路大概是:BIOS/UEFI → GRUB → 内核 → systemd(PID 1)→ 挂载根文件系统 → 启动各个服务单元 → 图形登录管理器(GDM/LightDM等)。任何一环依赖的资源缺失,都会让后面的环节失败。磁盘满了影响的是systemd那一层:系统在启动时要创建很多临时目录、更新系统状态、加载用户会话,这些操作都需要写入/var、/tmp、用户家目录等路径。当根分区剩余空间是0字节的时候,systemd的一些关键服务就会因为“No space left on device”而启动失败,尤其是一些带After=约束的服务,一旦起不来,后续服务全部阻塞,最终就停在一个黑屏或者卡死状态。
我处理过一个客户现场,现象就是开机后显示器黑屏,键盘灯能亮,但没有任何登录界面。我远程进去看了一眼journalctl -p err -b,发现systemd-tmpfiles-setup.service、rsyslog.service都因为写入失败挂了。把根分区腾出几个G后,重启一切正常。
提示:黑屏和卡死的优先级永远先看磁盘和内存,再看驱动。开机时先试试能否进入纯命令行(下文会讲),如果能进命令行,90%是磁盘满或者服务异常,而非硬件故障。
1.2 先分清:是根分区爆满,还是/boot爆满
这是很多人会混淆的地方。磁盘空间不足引发启动失败,常见原因有两个:
- 根分区
/爆满:影响上面说的systemd服务、临时文件写入、用户会话,导致黑屏、卡循环登录。 /boot分区爆满:内核更新时无法写入新内核与initramfs,系统重启后可能直接卡在GRUB或者停在加载内核阶段,表现可能是“紫屏/黑屏/花屏”,也可能直接GRUB rescue。
所以排查第一步,不是急着扩容,而是先确认到底哪个分区满了。我用过这样一组命令:
df -h df -i lsblk -fdf -h看空间,df -i看inode——注意,有少数场景是inode满了但空间还够,表现同样是“No space left on device”,但本质上不一样。lsblk -f则能看到分区表结构和文件系统类型,为后续扩容规划做准备。
1.3 确认问题的三个入口:GRUB菜单、recovery mode、multi-user.target
系统已经黑屏了,怎么进到命令行?三个办法,按顺序尝试:
入口一:GRUB菜单修改内核启动参数
开机时按住Shift(BIOS启动的机器)或者狂按Esc(UEFI模式),进入GRUB界面。选中默认条目,按e进入编辑模式,找到以linux开头的那一行,在末尾加上:
systemd.unit=multi-user.target然后按Ctrl+X启动。这个参数会强制systemd直接进入多用户纯命令行模式,跳过图形界面和管理器,只要内核能起来,基本就能拿到一个shell。
入口二:恢复模式(Recovery Mode)
GRUB菜单里一般有“Advanced options for Ubuntu”这一项,进去能看到带(recovery mode)的内核条目。选它进入后,会有一个恢复菜单,选择root选项就能拿到root shell。
注意:恢复模式下根文件系统通常是只读挂载的,要执行写入操作,先执行
mount -o remount,rw /。我第一次用的时候忘了这步,journalctl --vacuum-size直接报只读文件系统错误,排查了半天才反应过来。
入口三:用安装U盘/ Live USB修复
如果GRUB都进不去,或者选了内核直接panic,那就用Ubuntu安装U盘启动,选择“Try Ubuntu”,进入Live环境后挂载原系统的根分区来清理或备份数据。后面扩容操作中,非LVM分区的部分也经常需要Live环境配合。
拿到shell之后,第一件事就是看一眼最盘占用和文件系统状态:
df -h systemctl default如果磁盘确实满了,就按下一节的命令紧急腾空间。
2. 紧急自救:在命令行里先挤出几十GB活跃空间
2.1 用journald清理日志立竿见影
拿到命令行后的第一步,永远是先看系统的日志占了多少空间。systemd-journald这个组件会持续记录内核日志、服务日志、用户日志,配置不当的时候能把/var/log/journal吃到几十个GB。我之前在一台机器上见过/var/log/journal占满了整个根分区的80%。
优先执行这样两条:
journalctl --disk-usage journalctl --vacuum-size=200M--vacuum-size=200M的意思是保留最近日志,让journal总占用控制在200MB以内。执行完立刻释放了大量空间。如果journald占得不多,再看其他:
du -xh --max-depth=1 / 2>/dev/null | sort -rh | head -20这条命令用-x限制只看根分区内文件,--max-depth=1看一层目录,按大小倒序排。我最常用的场景就是看一下/var、/usr、/home、/tmp里到底谁最大。
2.2 apt与软件包缓存清理
Ubuntu的apt缓存和残留包是另一个隐藏磁盘杀手。执行:
apt clean apt autoremove -yapt clean是清空/var/cache/apt/archives下所有下载的deb包,这些包装完就没用了,但经常会占几个G。apt autoremove会移除那些“自动安装、现在没被任何包依赖”的软件包,注意看输出,别把需要的包误删了(不过裸机层面,比较少见)。
还有个容易被忽略的:
rm -rf /var/lib/apt/lists/*这是apt的索引和元数据缓存,占几个G很正常,清掉后下次apt update会重新拉,完全不影响系统。
2.3 清理旧内核与Docker残留
内核更新是/boot爆满的主要原因,但也会把根分区的/usr/lib/modules占满。先看当前运行的内核版本:
uname -a dpkg --list | grep linux-image保留当前内核版本和最近一两个版本,其余通过apt purge删除,例如:
apt purge linux-image-5.x.x-x-generic -y删除后记得执行update-grub,让GRUB菜单同步清理。
如果机器装了Docker,别忘了:
docker system prune -a这条会清理悬空镜像、停止的容器、未使用的网络和构建缓存,释放空间非常可观。但也提示一下,-a会把所有没有被正在运行容器引用的镜像都清掉,如果后续需要重新拉取镜像,要考虑网络和时间成本。不需要急着恢复生产就用这条,如果是生产环境建议只执行docker system prune -f先清悬空资源。
实操心得:紧急清理阶段的目标不是“优化体验”,而是“让系统能启动”。所以先看journal,再看apt缓存,再看旧内核,这三板斧下去基本能腾出5~15GB空间,足够支撑重启和后续扩容操作了。
3. 真正根治:磁盘容量扩展的完整实操
腾出空间只是缓兵之计,根源是磁盘容量规划不合理。要彻底解决,必须把容量扩大。我按三种常见磁盘布局分别给出操作路径。
3.1 动手前必须搞清楚的三种布局
先说清楚,扩容方式和分区布局强相关。先跑:
lsblk -f sudo pvs sudo vgs sudo lvs- 普通分区(非LVM):根分区是
/dev/sda1、/dev/nvme0n1p2这种直接分区,没有卷管理层。扩容时要么用growpart+resize2fs,要么借助Live U盘和GParted图形化处理。 - LVM逻辑卷:Ubuntu默认安装(使用整个磁盘时)经常采用LVM布局,根分区实际落在逻辑卷上,比如
/dev/mapper/ubuntu--vg-ubuntu--lv。LVM的好处是可以在卷组里有多余的物理空间时,一条命令在线扩展,不重启。 - 虚拟机磁盘:物理磁盘本身的容量是虚拟机软件(如VMware、VirtualBox、KVM)分配的,系统里看到的分区只是虚拟磁盘上的一部分。先在宿主机侧把虚拟磁盘大小扩大,再在系统内部扩展分区/文件系统。
我把三种情况对比如下:
| 布局类型 | 判断方法 | 核心扩容手段 | 是否必须停机 |
|---|---|---|---|
| 普通分区 | lsblk里根分区直接从sda等物理盘分出 | growpart+resize2fs;或GParted | 优先建议维护窗口 |
| LVM | lvs能看到逻辑卷 | lvextend+resize2fs | 可在线,通常不中断服务 |
| 虚拟机 | lsblk时磁盘总容量小于宿主分配容量 | 宿主侧扩虚拟磁盘,再系统内扩分区 | 视情况 |
注意:实际操作前永远先备份重要数据。扩容分区有风险,如果断电或者中途出错,最坏情况会导致数据不可读,所以我个人习惯是在操作前至少
tar备份关键目录,或者做一次快照(虚拟机里特别方便)。
3.2 LVM在线扩展:lvextend + resize2fs
LVM场景的扩容是我最喜欢的,因为可以在系统运行状态下完成,不需要进Live环境,也不用停机维护窗口。
假设我现在的布局是:
ubuntu-vg ├─ ubuntu-lv 挂载于 /第一步:查看卷组剩余空间。
sudo pvs sudo vgs sudo lvsvgs输出的VFree字段就是卷组里还没分配的可用物理空间。如果VFree是0,说明物理磁盘或者PV(物理卷)本身没预留空间,这时需要先扩展PV:
- 如果是虚拟机磁盘太小,先在宿主机扩容虚拟磁盘(见3.4),然后系统内执行
echo 1 > /sys/class/scsi_device/0:0:0:0/device/rescan重新扫描SCSI设备(路径里设备编号以实际为准,我常用ls /sys/class/scsi_device/查看)。 - 如果是物理机新增了一块硬盘,比如新增
/dev/sdb,则这样操作:
sudo pvcreate /dev/sdb sudo vgextend ubuntu-vg /dev/sdb如果卷组本来就有空闲空间,直接跳到第二步:
第二步:扩展逻辑卷。
sudo lvextend -L +20G /dev/ubuntu-vg/ubuntu-lv这条命令把逻辑卷扩大20GB。也可以直接指定目标大小,比如-L 100G表示扩展到100GB。注意-L +20G是“增加20G”,-L 120G是“扩容到120G”,两者含义完全不同,我见过有人用错导致逻辑卷大小和自己预期不一致。
第三步:扩展文件系统。
不同文件系统类型扩展命令不同,先判断:
lsblk -f /dev/ubuntu-vg/ubuntu-lv- 如果是
ext4:
sudo resize2fs /dev/ubuntu-vg/ubuntu-lv- 如果是
xfs(比如某些Rocky/Alma,但Ubuntu一般默认ext4):
sudo xfs_growfs /只要卷组里有空闲空间,这三步完成后df -h立刻就能看到根分区变大了,全程无需重启。
注意:现在新版的
lvextend在默认情况下已经会自动扩展文件系统(相当于替你执行了resize2fs)。我习惯用lvextend -r -L +20G,其中-r参数表示resize文件系统,一步到位。但为了兼容旧版本系统,我还是建议拆开执行,逻辑更清晰,出错也好定位。
3.3 非LVM场景:分区表扩展与resize2fs
非LVM场景稍微麻烦一点,因为分区表需要修改。方法取决于根分区在磁盘上的位置。
情况A:根分区前面有未分配空间,或者磁盘本身容量变大了(把根分区扩展到磁盘末尾之后)
这种最理想,用growpart扩展分区表条目,再用resize2fs扩展文件系统。假设根分区是/dev/sda2:
sudo growpart /dev/sda 2 sudo resize2fs /dev/sda2growpart实际上是在不影响数据的前提下,修改分区表让该分区的结束位置向后移动,把磁盘末尾的空闲空间“吸收”进来。执行前同样建议确认磁盘容量已经扩大(物理机换大硬盘,或虚拟机扩容虚拟磁盘)。
情况B:根分区后面跟着其它分区,无法向后扩展
这种情况根分区被挡在中间,没法直接向后扩。我的方案是用GParted Live或者Ubuntu Live USB启动,图形化把前面的数据分区缩小、腾出空间、再把根分区扩大。步骤大致为:
- 用启动盘进入Live环境。
- 如果根分区所在磁盘有交换分区且刚好挡在中间,先
swapoff并删除/缩小交换分区,优先把空闲空间给根分区腾出来(必要时之后再重建swapfile)。 - 在GParted里缩小根分区后面的那个分区,腾出空闲空间。
- 把根分区向后面扩展到目标大小。
- 应用操作后退出Live环境,正常启动系统。
这个过程我一般不建议在运行中的系统上直接操作挂载中的根分区,GParted会拒绝修改已挂载分区,Live环境里根分区未挂载,安全性高一些。
3.4 虚拟机场景:先在宿主侧扩容,再让系统识别
很多“Ubuntu黑屏无法启动”其实是虚拟机里的系统,比如VMware、VirtualBox、Proxmox/KVM环境。这类环境扩容链路多了一个宿主侧操作,很多人卡就卡在“宿主里已经把磁盘调大了,但系统里看不到”。
以VMware为例,先关机或在线执行磁盘扩展,把虚拟磁盘从50GB扩到100GB(不同虚拟化平台的操作入口不同,但思路一致)。随后进入Ubuntu命令行:
lsblk这时你会发现磁盘(比如/dev/sda)总容量变成了100GB,但分区(/dev/sda2)还是原来的大小。此时只需要做两件事:
- 让系统重新读取磁盘的新容量(虚拟机里通常重启后自然生效,但有些平台支持在线扫描):
echo 1 > /sys/class/scsi_device/0:0:0:0/device/rescan不同虚拟化平台识别新容量的方式略有差异,最简单可靠的方式其实是重启系统,然后再执行lsblk确认容量。
- 如果是LVM,先扩展PV:
sudo pvresize /dev/sda2然后再回到3.2的第二步执行lvextend+resize2fs。
如果是非LVM分区,执行3.3的growpart+resize2fs即可。
实操心得:虚拟机扩容的时候,强烈建议在宿主侧先做快照。虽然扩展分区本身一般不损坏数据,但虚拟机磁盘扩容后一旦分区表操作中途断电,没有快照就只能靠备份恢复,太被动了。
4. 扩容过程和扩容后最容易踩的坑
4.1 黑屏问题的其他诱因:swap、内存溢出、驱动冲突排查
先说明一下,磁盘扩容解决的是“磁盘满”这一大类问题。但黑屏无法启动这里其实不止一个诱因,我自己排障时遇到过好几种情况,如果磁盘腾出来之后重启依然黑屏,需要继续排查以下三点:
swap太小或者没配置:内存不够时,系统会尝试用交换分区,如果交换分区在扩容过程中被删了或者太小,图形界面启动时内存耗尽,也会表现为黑屏。可以先检查:
free -h swapon --show如果swap为0且内存吃紧,建议创建swapfile:
sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile然后在/etc/fstab里加一行/swapfile none swap sw 0 0。
显示管理器或者图形驱动问题:如果磁盘空间充足、内存充足、swap正常,但黑屏依旧,那就可能是GPU驱动和当前内核版本不配套。在命令行下可以这样重启显示管理器:
sudo systemctl restart gdm3或者查日志:
journalctl -b -g "(Failed|ERROR|Traceback)" | tail -50如果是NVIDIA驱动的问题,日志里一般会有模块加载失败的报错,这时才需要去处理驱动。
4.2 扩容后引导失败的排查思路
扩容后最可怕的不是容量不够,而是重启后系统直接进不了GRUB。以下我根据实际经验整理了排查优先级:
分区表被改动导致UUID变化
如果你用fdisk/parted手动删除重建分区,而不是用growpart,那么分区的UUID可能发生变化,而/etc/fstab里记录的还是旧UUID,系统挂载根分区时就会失败。这就是为什么我强烈推荐growpart和lvextend——它们不改UUID。
如果不小心改了UUID,启动时会停在一个类似(initramfs)的提示符。此时可以在initramfs里用blkid查看新UUID,然后在/etc/fstab里修改,或者用update-initramfs -u重新生成initramfs。这些操作在Live环境中做会更顺手。
GRUB引导安装位置不对
扩容时如果动过磁盘首部区域(比如从磁盘头部腾空间),可能导致GRUB引导代码丢失,表现为开机直接黑屏或者提示“找不到引导程序”。处理方式是进Live环境后挂载根分区,执行:
sudo mount /dev/sda2 /mnt sudo mount /dev/sda1 /mnt/boot # 如果有独立boot分区 sudo grub-install /dev/sda sudo update-grub然后重启。我遇到过一次这种情况,就是图省事直接删了分区重建,结果引导丢,还好用Live U盘救回来了。
误删了内核或者initramfs
清理旧内核时apt purge可能会“手滑”把当前内核也删了。遇到这种情况,进Live环境挂载根分区后:
sudo chroot /mnt apt install linux-image-generic update-grub exit然后重启。
4.3 常见问题速查表
我把排障过程中碰到的典型问题整理成一个速查表,方便现场快速对照:
| 现象 | 可能原因 | 排查/修复命令 |
|---|---|---|
| 开机黑屏,Ctrl+Alt+F2无响应 | 磁盘满,systemd服务卡死 | df -h,清除journal和apt缓存 |
| 进GRUB选择内核后黑屏 | /boot分区满或内核损坏 | dpkg --list | grep linux-image,清理旧内核 |
开机提示(initramfs) | fstab中UUID失效或根分区挂载失败 | blkid查看UUID,修改/etc/fstab |
| 扩容后分区未变大 | 卷组没有剩余空间,或者没执行resize2fs | vgs看VFree,resize2fs确认执行 |
| 扩容后显示容量变大但写入仍报满 | inode耗尽 | df -i确认,删除大量小文件 |
GRUB提示no such device | 引导丢失 | Live环境执行grub-install和update-grub |
最后再补充一个我个人的习惯:扩容完成之后,别急着直接投入高负载使用,先重启一次验证完全正常,再让业务跑起来。Linux扩容这件事,绝大多数情况下都不难,但每一步都涉及分区表、文件系统这些核心结构,谨慎一点永远不会吃亏。希望这篇记录能帮到你,你机器的空间规划,也值得在这次处理完之后好好重新盘一盘。