前言:恐慌的开端
“周末的早晨,告警邮件如期而至。” —— 这恐怕是每个运维工程师的噩梦。当我尝试启动一台重要的 GitLab 虚拟机(运行在 ESXi 上的 Ubuntu Server)时,屏幕上滚动着熟悉的启动日志,最后却无情地停在了一行红色的 [FAILED]
上:
[FAILED] Failed to start Create Volatile Files and Directories.
see 'systemctl status systemd-tmpfiles-setup.service' for details.
...
[FAILED] Failed to start Network Name Resolution.
...
系统无法正常启动,服务全面中断。这就是我们今天故事的开始:一次由磁盘空间耗尽引发的“血案”,以及一次从紧急救援到彻底根治的全过程记录。
Part 1:紧急救援 - 在只读的世界里杀出一条血路
systemd-tmpfiles-setup.service
失败通常指向一个根本原因:根分区 (/
) 被 100% 占满了。系统连创建临时文件的空间都没有,后续所有服务自然接连崩溃。
我们的首要目标是进入系统,清理出哪怕只有几百MB的空间,让系统能成功启动。
- 进入恢复模式:重启虚拟机,在 GRUB 菜单选择 "Advanced options for Ubuntu",然后进入 "Recovery mode"。
获取读写权限的 Shell:在恢复菜单中,选择
root
(Drop to root shell prompt)。此时你会进入一个命令行,但注意,文件系统默认是只读 (read-only) 的。必须执行以下命令,将其重新挂载为可读写,否则任何删除操作都会失败:mount -o remount,rw /
定位并清理空间:现在,我们可以开始“瘦身”了。
- 确认病因:
df -h
果不其然,根分区/
的Use%
显示为100%
。 - 分析元凶:通过
du -h --max-depth=1 /var | sort -rh
逐层分析,我们很快定位到/var/lib/docker
(47G) 和/var/lib/snapd
(3.9G) 是两大元凶。 安全清理:
清理 Docker:Docker 提供了安全清理的命令,它只会删除未被使用的资源,不会影响正在运行的服务。
# 清理所有未使用的容器、网络、镜像和构建缓存 docker system prune
- 确认病因:
- **清理 Snap**:Snap 会保留旧版本的包,非常占用空间。以下脚本可以安全地删除所有被禁用的旧版本:
snap list --all | awk '/disabled/{print $1, $3}' | while read snapname revision; do snap remove "$snapname" --revision="$revision"; done
经过这两步,我们成功释放了数GB的空间。此时,执行 reboot
,虚拟机终于正常启动了!
Part 2:防患未然 - 在扩容前备份一切
系统虽然恢复了,但治标不治本。为了彻底解决问题,我们决定扩容磁盘。但在进行这种“高危操作”之前,备份是雷打不动的铁律。
幸运的是,这台 GitLab 是通过 Docker 数据卷部署的,所有数据都映射在主机的 /mnt/gitlabdata
目录下。
我们使用 tar
命令进行打包,但有一个技巧:必须将生成的备份包自身从打包范围中排除,否则会陷入无限循环。
# -C 参数先切换到目标目录,避免打包时带有绝对路径
# --exclude 参数排除了备份文件自身
sudo tar --exclude='gitlab-backup-*.tar.gz' \
-czvf /mnt/gitlabdata/gitlab-backup-$(date +%F).tar.gz \
-C /mnt/gitlabdata .
执行完毕后,一个以日期命名、包含所有数据的完整备份包静静地躺在了 /mnt/gitlabdata
目录中。我们心中大定。
Part 3:核心操作 - 扩容硬盘并让系统识别
扩容分为两步:在 ESXi 层面扩大虚拟磁盘,然后在 Ubuntu 系统内部让分区和文件系统识别到新空间。
1. ESXi层面:搞定“快照”拦路虎
- 关机并尝试扩容:我们先关闭虚拟机,在 ESXi 的“编辑设置”中尝试将硬盘从 60GB 改为 160GB。
- 遭遇报错:“设备‘3’的操作无效”。这是一个经典错误,99% 的原因是虚拟机存在快照。ESXi 不允许在有快照的情况下修改虚拟磁盘的结构。
- 解决:右键虚拟机 -> 快照 -> 快照管理器,点击 “全部删除”。注意,这里的“删除”实际上是将快照数据合并回主磁盘,会保留所有数据。等待合并任务完成后,我们再次编辑设置,成功将硬盘容量扩展到了 160GB。
2. Ubuntu系统层面:从分区到文件系统
这是最关键也最容易出错的一步。
- 第一道坎:找对设备名
教程常以 /dev/vda 为例,但我们的系统识别为 /dev/sda。永远不要盲从教程,lsblk 命令才是你的真相之源。
lsblk
# NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
# sda 8:0 0 160G 0 disk
# └─sda1 8:1 0 60G 0 part /
输出清晰地告诉我们:硬盘是 /dev/sda
,需要操作的分区是 /dev/sda1
。
- 第二步:扩展分区 (parted)
parted 是一个强大的分区工具,它的操作对象是整块硬盘。
sudo parted /dev/sda
进入 (parted)
交互模式后,我们执行 resizepart
命令。
(parted) resizepart
Partition number? 1
End? [64.4GB]? 100%
输入分区号 1
,并将结束位置设为 100%
,这是一个绝佳的技巧,能自动将分区扩展到磁盘的全部可用空间。完成后输入 quit
退出。
- 第三步:扩展文件系统 (resize2fs)
分区边界虽然扩大了,但分区内部的文件系统(你可以理解为货架)还停留在旧的大小。resize2fs 的作用就是通知文件系统去铺满整个分区。它的操作对象是分区。
sudo resize2fs /dev/sda1
命令瞬间执行完毕。
最后验证
df -h
输出结果中,/dev/sda1
的 Size 一栏赫然显示着 157G
。至此,扩容大功告成!
总结
这次从宕机到扩容的经历,再次印证了几个系统管理的基本原则:
- 监控是生命线:主动的磁盘空间监控能避免 99% 的此类事故。
- 理解工具而非死记命令:知道
lsblk
比记住/dev/sda
重要得多;理解“硬盘vs分区”的区别,才能正确使用parted
和resize2fs
。 - 快照是双刃剑:快照是备份和恢复的利器,但也是日常运维(如扩容)的“拦路虎”。要养成定期清理、合并快照的习惯。
- 备份,备份,还是备份:在任何高危操作前,一个可靠的备份是你敢于点击“确认”按钮的最大底气。
希望这次的实战记录,能为遇到类似问题的朋友提供一份清晰的行动指南。
版权属于:soarli
本文链接:https://blog.soarli.top/archives/759.html
转载时须注明出处及本声明。