磁盘满不是「删点东西」就完事。先分清是空间满了还是 inode 满了,再找出真正占地方的东西,最后把会持续增长的部分限额,否则过几天还会满。
第 0 步:确认是哪一种「满」
df -h
df -i
df -h 看空间。df 的手册说明它显示的是「文件系统剩余空间」,-i 则是:
list inode information instead of block usage
如果空间还有、但写入报 No space left on device,基本就是 inode 用完了,常见于大量小文件。
第 1 步:找大目录
du -xh --max-depth=1 / | sort -h
进入最大的目录继续看,通常落在这几处:
/var/log:系统与应用日志;/var/lib:数据库、Docker、软件数据;/var/cache:包缓存;/home或/root:下载的文件、备份包;- Docker 的 overlay 目录(通常在
/var/lib/docker)。
du 的手册提醒:它估算的是磁盘占用,与文件「表观大小」可能不同(稀疏文件、内部碎片等)。如果数字对不上,别急着怀疑工具。
第 2 步:找大文件
find / -xdev -type f -size +200M -exec ls -lh {} \; 2>/dev/null
-xdev 不跨文件系统,避免扫到挂载的其他磁盘。重点看:旧备份包、导出的 SQL、核心转储(core)、日志归档。
第 3 步:查「已删除但仍被占用」的文件
这是最容易被忽略的一类。现象是 df 显示快满,但 du 加起来远小于已用空间。
lsof +L1 2>/dev/null | head -50
找到对应进程后,按顺序处理:
- 能重启的服务直接重启;
- 不能重启的,用
truncate -s 0 <文件路径>(对日志类文件)或写空/proc/<pid>/fd/<fd>; - 处理完再看
df -h。
注意不要用 rm 去删一个被进程占用的日志:文件从目录消失,但空间依然被占着。
第 4 步:分类清理
系统日志
journalctl --disk-usage
journalctl --vacuum-size=200M
journalctl --vacuum-time=7d
journald.conf 手册对 SystemMaxUse 的定义是:控制 journal 最多能占多少磁盘;默认值按文件系统大小的 10%、上限 4G。可以直接设置上限:
# /etc/systemd/journald.conf
SystemMaxUse=200M
systemctl restart systemd-journald
传统日志
/var/log 下的 *.log、*.gz 按时间清,别用 rm -rf /var/log/*。正确的做法是让 logrotate 管。
包缓存
apt clean
apt autoremove --purge
Docker
docker system df
docker builder prune
docker image prune
docker image prune -a
顺序是:构建缓存 → 悬空镜像 → 未使用镜像。docker volume prune 要慎用,命名卷里可能是数据库数据。
数据库与备份
- 二进制日志、慢查询日志、旧备份包;
- 备份文件不要长期放本机,按保留策略移到另一台机器或对象存储。
第 5 步:防复发
给 journal 设上限
见上面的 SystemMaxUse。
给应用日志配 logrotate
logrotate 的官方说明是:轮转、压缩、删除与邮寄日志,可按天/周/月或按大小触发。新建 /etc/logrotate.d/myapp:
/var/log/myapp/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
copytruncate
}
copytruncate 适合那些不会自己重开日志文件的程序:先复制再清空原文件,避免重启服务。
手动测试配置(不实际轮转,只校验语法并输出过程):
logrotate -d /etc/logrotate.d/myapp
给 Docker 日志设上限
/etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
改完重启 Docker;已有容器要重建才生效。
监控阈值
对磁盘使用率和 inode 使用率都设告警,阈值建议 80%。只盯空间不盯 inode,仍会突然写不进去。
常见问题对照
| 现象 | 优先检查 |
|---|---|
df 满但 du 不大 |
lsof +L1 找已删除仍被占用的文件 |
| 有空间但写不进去 | df -i 看 inode |
| 删了日志空间没回来 | 进程仍持有句柄,重启或 truncate |
| 日志反复撑满 | 没配 logrotate,或 logrotate 条件不匹配 |
| Docker 目录越来越大 | 构建缓存 + 未限制日志大小 |
| 数据库目录异常增长 | binlog、慢日志、未清理的旧表 |
一句话总结
先 df -h 与 df -i 分清空间还是 inode → du 找目录 → find 找大文件 → lsof +L1 查幽灵占用 → 分类清理 → 用 journald、logrotate、Docker 日志上限防复发。