VMware 虚拟机 Linux 磁盘满清理 + 虚盘收缩教程
适用系统:Debian / Ubuntu(宝塔面板) 示例现状:168.2GB / 195.8GB,剩余约 27.6G
原理:VMware 精简磁盘不会自动回收已删除文件占用的块。必须在虚拟机内部把空闲区域写 0,关机后在 VMware 执行【压缩】,宿主机磁盘空间才会真正释放。
本版已按宝塔面板环境复核修订:原脚本中会误删 MySQL/PHP 的 socket、填零数据未落盘、终端断开留下满盘文件、面板日志路径写错等问题均已修正。
一、操作前确认(3 件事)
- 快照:VMware 里【虚拟机】→【快照】→【快照管理器】,有快照先删除(会合并到当前磁盘)。有快照时压缩不可用或回收不到空间。
- 磁盘类型:只有「按需分配(精简置备)」的虚拟磁盘,压缩才有意义。如果创建时勾选了「立即分配所有磁盘空间」,宿主机占用本来就是满的,压缩不会变小。
- 分区:本教程只处理
/所在分区。先执行df -h,如果/www、/data是独立分区,需要对每个分区分别填零。
二、注意事项
- 填零期间根分区会 100% 占满,面板打不开、MySQL/网站写日志报错,属于正常现象,不要重启虚拟机。
- 建议在业务低峰期执行。如果数据库写入不能中断,可以先在面板里停止 MySQL,填零完成后再启动。
- 必须【正常关机】,暂停状态无法压缩磁盘。
- 填零时出现
No space left on device是预期报错,属于正常现象。 - 宝塔 Web 终端断开不会中断填零(脚本已放后台);如果虚拟机断电或被强制关机,重新登录后第一时间执行
rm -f /zero.fill。
三、步骤 1:查看占用
宝塔面板左侧【终端】执行(root):
df -h /
du -sh /* 2>/dev/null | sort -rh | head -15
du -sh /www/wwwlogs /www/backup /www/server/data 2>/dev/null
宝塔机器常见的大头:
/www/wwwlogs:站点访问/错误日志/www/backup:站点/数据库备份(确认后再删)/www/server/data:MySQL 数据 + binlog(不要直接 rm)/var/log、/var/lib/docker(有 Docker 时)
能手动清的先清,空闲空间越大,后面越稳。
可选:清空站点日志(会丢失历史访问记录)
# 清空全部站点日志(保留文件,nginx 可以继续写入)
find /www/wwwlogs -maxdepth 1 -type f -name "*.log" -exec truncate -s 0 {} \;
# 删除已轮转的旧日志
find /www/wwwlogs -maxdepth 1 -type f \( -name "*.log.gz" -o -name "*.log.1" \) -delete
MySQL binlog 很大时不要用 rm,用 PURGE(root 密码可在面板【数据库】页面查看):
mysql -uroot -p -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY);"
四、步骤 2:创建脚本
在宝塔终端一次性粘贴下面整段(包含结尾的 EOF),会在 /root 生成 vm-shrink.sh:
cat > /root/vm-shrink.sh <<'EOF'
#!/bin/bash
# VMware 虚拟机 Linux 磁盘清理 + 空闲空间填零(宝塔面板版)
# 适用:Debian / Ubuntu,root 执行
# 用法:
# bash /root/vm-shrink.sh status 查看占用
# bash /root/vm-shrink.sh clean 安全清理(可选)
# bash /root/vm-shrink.sh fill 后台填零
case "$1" in
status)
echo "【根分区】"
df -h /
echo
echo "【根目录占用 TOP 15】"
du -sh /* 2>/dev/null | sort -rh | head -15
echo
echo "【宝塔常见大目录】"
du -sh /www/wwwlogs /www/backup /www/server/data 2>/dev/null
;;
clean)
echo "---- 清理前 ----"
df -h /
apt clean 2>/dev/null
journalctl --vacuum-size=50M 2>/dev/null
# 只删 3 天前的普通文件;-type f 不会删掉 /tmp 下的 mysql.sock、php-cgi-*.sock
find /tmp /var/tmp -maxdepth 1 -type f -mtime +3 -delete 2>/dev/null
# 宝塔面板日志:新版目录是 logs,老版是 log
rm -rf /www/server/panel/logs/* /www/server/panel/log/* 2>/dev/null
echo "---- 清理后 ----"
df -h /
;;
fill)
if [ -e /zero.fill ]; then
echo "已存在 /zero.fill,请先执行:rm -f /zero.fill"
exit 1
fi
echo "---- 后台开始填零 ----"
# nohup + setsid:关闭宝塔终端不会中断;结束后自动 sync 并删除填充文件
nohup setsid bash -c 'dd if=/dev/zero of=/zero.fill bs=1M; sync; rm -f /zero.fill; echo ZERO_FILL_DONE' > /root/zero_fill.log 2>&1 &
echo "已启动。查看进度:df -h / 或 du -h /zero.fill"
echo "结束标志:cat /root/zero_fill.log 出现 ZERO_FILL_DONE"
;;
*)
echo "用法:bash $0 {status|clean|fill}"
;;
esac
EOF
小提示:粘贴后如果还停在 > 提示符,说明结尾的 EOF 没粘上,手动输入 EOF 回车即可。
也可以用【文件】→ 进入 /root → 新建文件 vm-shrink.sh → 粘贴内容 → 保存。
五、步骤 3:安全清理(可选)
bash /root/vm-shrink.sh clean
做四件事:
- 清 apt 缓存;
- 收缩 systemd 日志;
- 只删除
/tmp、/var/tmp下 3 天前的普通文件(不会动 socket,宝塔的mysql.sock、php-cgi-*.sock安全); - 清空宝塔面板自身日志(
logs/log两个路径都尝试)。
不会碰:站点日志、网站备份、数据库文件。
六、步骤 4:后台填零
bash /root/vm-shrink.sh fill
提醒:如果数据库写入不能中断,建议先在面板【软件商店】→【MySQL】→【停止】,填零完成后再启动(见第二节注意事项)。
脚本会把 dd 放到后台(nohup setsid),关掉宝塔终端、关浏览器都不会中断。
查看进度:
df -h /
du -h /zero.fill
- 可用空间接近 0 表示快写满了,属于正常;
- 写满后脚本会自动
sync、删除/zero.fill,并在日志里写入ZERO_FILL_DONE:
cat /root/zero_fill.log
看到 ZERO_FILL_DONE 表示填零结束、填充文件已删除。
中途中止填零(如临时有事需要停止):
pkill -f "of=/zero.fill" && rm -f /zero.fill
执行后填零立即停止、空间立即释放,可以正常继续其他操作;之后想继续填零,重新执行一次 bash /root/vm-shrink.sh fill 即可。
七、步骤 5:确认
ls -l /zero.fill # 应提示 No such file
df -h / # 可用空间应恢复到 20G 以上(取决于清理掉了多少)
八、步骤 6:正常关机
在终端执行:
shutdown -h now
或 VMware 菜单【虚拟机】→【电源】→【关闭客户机】。
不要用「暂停」,暂停状态不能压缩磁盘。
九、步骤 7:VMware 压缩
- 确认虚拟机已完全关机;
- VMware 选中虚拟机 →【编辑虚拟机设置】→【硬盘】→ 右侧【磁盘实用工具】→【压缩】;
- 等待完成,期间不要打断。
如果【压缩】是灰的:检查是否真的关机、是否有快照、磁盘是否为独立磁盘。
十、步骤 8:开机验证
- 虚拟机内
df -h /:容量不变(还是 195.8G),但可用空间变多; - 宿主机上查看该虚拟机目录里的
.vmdk文件,体积应明显变小。
压缩只回收宿主机磁盘占用,不会缩小虚拟机内的分区容量。
十一、兜底:终端断开 / 中途断电
如果因为强制关机、宿主机断电等原因留下了填充文件:
rm -f /zero.fill
rm 只是删除文件,不需要额外空间,执行后空间立即释放。
十二、附:本次修订说明(原脚本的问题)
- 交互式
read不能直接粘贴执行:终端是逐行交给 shell 的,read会把后面粘贴的if [[ ... ]]当成输入,选项失效。改为status / clean / fill子命令,不需要交互。 rm -rf /tmp/*是宝塔上的高风险操作:宝塔的 PHP-FPM socket(/tmp/php-cgi-*.sock)和 MySQL socket(/tmp/mysql.sock)都在/tmp,删掉后网站 502、面板连不上数据库。改为只删 3 天前的普通文件(-type f不会匹配 socket)。- 面板日志路径写错:宝塔实际是
/www/server/panel/logs,原脚本的/www/server/panel/log通常不存在;已同时兼容。 - 漏掉真正的大头:站点日志
/www/wwwlogs、备份/www/backup、MySQL binlog 才是宝塔机器最常见的空间占用,原脚本没有处理;已补充查看命令和安全清理方式。 - **
dd后缺少sync**:数据可能还在内存里就被rm掉,末尾一段空闲块实际没写零,VMware 压缩回收不到。改为dd → sync → rm。 - 宝塔 Web 终端断开会杀掉 dd:留下写满的
/zero.fill,根分区 100% 满。改为nohup setsid后台执行,断终端不影响,并在结束后自动清理。 - 补上压缩前提:快照必须先删、磁盘必须是按需分配、虚拟机必须完整关机;压缩不改变虚拟机内的分区容量。
【END】