前言
由于前两天的 PHP 漏洞,我登录服务器进行漏洞修复时,顺手看了一眼磁盘,发现根盘占用率这几年越来越高:40G 的盘已经用掉 32G,使用率到了 85%。虽然还没真正爆盘,但再装点东西或者日志一涨,很容易出问题。
这次我没有一上来就删文件,而是按“先定位、再清理、最后防反弹”的顺序,把服务器盘和 Docker 里的青龙面板一起梳理了一遍。本文记录的就是这次清理过程。文中的图片是我事后按当时的命令输出重绘的示意图,不是真实截图。
先定位:空间到底被谁占了
我先用 df -h 确认是 /dev/vda3 快满了,然后用不跨文件系统的 du -x 逐层定位:
1 | df -h |
一开始直接跑 du -sh / 得到 37G,比 df 的 32G 还大,后来才意识到是 Docker 的 overlay2/…/merged 挂载点被重复统计了。加上 -x 之后数据就正常了。
定位结果很明确:/www 13G,/var 11G,/usr 3.8G,/home 1.1G。真正的大头在宝塔备份、系统日志和 Docker,而不是青龙面板本身。
Docker 先看账本,不急着 prune
我先看了 Docker 的占用明细:
1 | docker system df |
当时三个镜像都在运行中:青龙、qd、redis。容器可写层里青龙约 1.96GB,本地卷合计约 891MB,构建缓存为 0。也就是说 Docker 总共约 4G,不是 32G 的主因。
进入青龙容器可写层继续看,发现大部分是缓存和临时文件:
/.pnpm-store/v3 约 1.1G
/ql/.tmp 约 281M,里面是 7 个月前的 data.tgz、static.zip 等更新临时包
/root/.cache 约 119M
/root/.npm 约 70M
/tmp/pip-unpack-* 约 61M
这些都可以在容器内安全清理。注意不要在宿主机直接 rm -rf Overlay2 的 diff 目录,正确做法是进入容器删除,让 Overlay 正常记录删除操作。
1 | docker exec -it qinglong sh -lc ' |
同时删了一个 LINKS=0 的无引用本地卷,约 160.9MB。没有执行 docker volume prune,避免误删以后还要用的卷。
宝塔面板备份:真正的大头
继续看 /www,发现 /www/backup 有 7.7G,其中 /www/backup/panel 一个目录就 7.5G。进去一看,是从 2024-04-27 到 2026-10-22 的每日面板备份 zip,900 多个文件,连续积累了两年多。
我的处理方式是保留最近 7 天,其余删除。先预览,再删除:
1 | ls /www/backup/panel/*.zip | sort | head -n -7 |
宝塔面板里没有直接显示“备份面板”的计划任务,所以我没有去改某个配置文件,而是用自定义脚本加 crontab 做保留策略。新建 /www/server/panel/script/clean_panel_backup.sh:
1 |
|
赋权后加入 crontab,每天凌晨 3 点执行:
1 | chmod +x /www/server/panel/script/clean_panel_backup.sh |
这样既保留最近一周的面板备份,又不会再次无限累积。
journal 日志:3.9G 清到 500M
/var/log 当时 4.2G,其中 /var/log/journal 3.9G。这个清理没有风险:
1 | journalctl --disk-usage |
为了避免以后再长回去,我又在 /etc/systemd/journald.conf 里加了上限:
1 | SystemMaxUse=500M |
然后重启 systemd-journald。
lsof +L1 的 deleted 文件:大部分不用管
中途我也跑了 lsof +L1 | grep deleted,看到 php-fpm、mysqld、BT-Panel、docker 等进程持有 deleted 文件。但关键要看 SIZE/OFF 列:大量项都是 0,真正有大小的只有十几个 MB。
我的结论是:只有持有 deleted 可执行文件的系统服务在低峰期值得重启,比如 systemd-logind、agetty、unattended-upgrades;php-fpm、mysqld、BT-Panel、docker 持有的临时/信号量文件不建议仅为它们重启业务。这批文件也不是磁盘占用主因。
青龙依赖怎么判断必要和冗余
青龙的依赖冗余,不能只看“装了多少”,而要看“脚本实际用了什么”。我的做法是:
在青龙面板“依赖管理”里看已安装列表和状态;
命令行辅助确认:
1 | docker exec -it qinglong pip list |
运行主要任务,如果报 Cannot find module 'xxx' 或 ModuleNotFoundError: No module named 'xxx',这个依赖就是必要的;
状态为“安装失败”、且完全没印象的依赖,优先清理;
清理后在“设置 → 历史数据保留与手动清理”里清除 Node/Python 依赖缓存。
这次先清了缓存,依赖本身没有大动。后续准备按“删一个、跑任务、看是否报错”的方式慢慢精简,避免误删导致脚本失败。
清理结果和防反弹
全部处理完,根盘从 32G 已用降到 20G,使用率从 85% 降到约 50%。
这次真正起作用的几块是:
| 项目 | 约释放 |
|---|---|
| /www/backup/panel 旧 zip | 约 7.4G |
| journal | 约 3.4G |
| 青龙容器缓存 | 约 1.6G |
| 无引用 Docker 卷 | 约 160M |
为了防止反弹,我又做了三件事:
- 用 crontab 每天清理 7 天前的面板备份;
- 限制 journal 最大 500M;
- 给 Docker 配置日志轮转,编辑 /etc/docker/daemon.json:
1 | { |
然后重启 Docker。注意这个配置主要影响之后新建的容器,已有容器需要重建才生效。
后记
这次清理最大的感受是:磁盘告警不要上来就 rm,先用 df、du -x、docker system df 把账算清楚。看起来吓人的 lsof +L1 deleted 文件,很多其实只有 0 字节;真正吃掉空间的,往往是宝塔备份、journal 这类“每天都在长、但平时没人看”的目录。
青龙依赖也是一样,依赖列表本身不能说明必要性,最终还是要以脚本能不能正常跑为准。先清缓存,再慢慢删依赖,比一次性大清理稳妥得多。
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub Issues