在Debian系统运维中,logrotate配置不当是导致磁盘空间被日志文件占满的最常见原因之一。具体来说,当logrotate的轮转周期设置过长、压缩策略未启用、或者轮转后的旧日志没有被正确删除时,日志文件会以惊人的速度膨胀,几天之内就能把几十GB的磁盘塞满。解决这个问题的核心在于:重新审视并修正logrotate的全局配置文件和各服务的独立配置文件,确保日志按时轮转、旧日志被压缩并在合理周期内清除。下面我会把这个问题从根因分析到完整解决方案,一次性讲透。
为什么logrotate配置不当会导致磁盘满?
logrotate是Debian系统默认安装的日志轮转工具,它的工作原理是按照设定的时间或大小条件,将正在写入的日志文件重命名、压缩,然后创建新的空日志文件继续写入。但很多运维人员在部署服务后,从来没有仔细检查过logrotate的实际配置,或者只用了系统默认配置。问题往往出在以下几个方面:第一,默认配置中compress参数可能被注释掉了,导致旧日志不压缩直接保留;第二,rotate参数设为0或者数值过大,意味着旧日志永远不会被删除;第三,某些服务(如Nginx、MySQL、Docker)的日志文件根本没有被logrotate纳入管理,这些日志以原始大小无限增长;第四,daily、weekly、monthly这些时间周期的脚本可能没有被cron正确调用,导致轮转根本没有执行。
如何快速排查当前磁盘占用情况
当你发现磁盘告警时,第一步不是去改配置,而是先搞清楚哪些文件在吃空间。执行以下命令可以快速定位大文件:
du -h --max-depth=1 /var/log | sort -hr | head -20
这条命令会列出/var/log目录下占用空间最大的前20个目录或文件。通常你会看到类似/var/log/nginx/access.log、/var/log/mysql/error.log、/var/log/syslog这样的文件动辄几个GB。如果你用的是Docker环境,还要检查/var/lib/docker/containers/目录下的JSON日志文件,这些文件同样可能非常庞大。
du -h --max-depth=1 /var/lib/docker/containers | sort -hr | head -10
Debian系统logrotate的核心配置文件解读
Debian的logrotate主配置文件位于/etc/logrotate.conf,这个文件定义了全局默认行为。打开它你会看到类似这样的内容:
# see "man logrotate" for details
# rotate log files weekly
weekly
# keep 4 weeks worth of backlogs
rotate 4
# create new (empty) log files after rotating old ones
create
# use date as a suffix of the rotated file
dateext
# uncomment this if you want your log files compressed
#compress
# RPM packages drop log rotation information into this directory
include /etc/logrotate.d
# no packages own wtmp and btmp -- we'll rotate them here
/var/log/wtmp {
missingok
monthly
create 0664 root utmp
rotate 1
}
/var/log/btmp {
missingok
monthly
create 0660 root utmp
rotate 1
}
注意看#compress这一行是被注释掉的,这就是很多Debian系统日志不压缩的根源。全局默认rotate 4配合weekly意味着只保留4周的日志,但如果某个服务的独立配置覆盖了这个值,问题就来了。另外,include /etc/logrotate.d这一行说明所有放在/etc/logrotate.d/目录下的配置文件都会被加载,每个服务通常都有自己的配置文件在这里。
各常见服务的logrotate独立配置详解
进入/etc/logrotate.d/目录,你会看到一堆配置文件。以Nginx为例,它的配置通常是这样的:
/var/log/nginx/*.log {
daily
missingok
rotate 52
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid`
endscript
}
这个配置看起来合理:每天轮转、保留52份、压缩、延迟压缩。但如果你的Nginx访问量巨大,每天产生的日志可能有几个GB,52份就是上百GB。对于高流量站点,rotate 52明显太多了。再看MySQL的配置:
/var/log/mysql/*.log {
daily
rotate 7
missingok
notifempty
compress
postrotate
if test -x /usr/bin/mysqladmin && \
/usr/bin/mysqladmin ping &>/dev/null
then
/usr/bin/mysqladmin flush-logs
fi
endscript
}
MySQL的rotate 7看起来合理,但如果你的错误日志增长极快,7天的累积也可能很可观。关键是要根据实际业务调整这些数值。
Docker容器日志不被logrotate管理的问题
这是一个非常容易被忽视的坑。Docker容器的日志默认存储在/var/lib/docker/containers/<容器ID>/<容器ID>-json.log,这些文件不受系统logrotate管理。如果容器持续输出大量日志,这些JSON文件会无限增长。解决办法有两个:一是在Docker daemon配置中限制日志大小,编辑/etc/docker/daemon.json:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
二是手动为Docker日志创建logrotate配置,在/etc/logrotate.d/下新建docker-logs文件:
/var/lib/docker/containers/*/*.log {
daily
rotate 7
compress
missingok
notifempty
copytruncate
}
注意这里用了copytruncate参数,因为Docker容器的日志文件是持续打开的,不能通过重命名来轮转,必须复制后截断原文件。
紧急情况下如何快速释放磁盘空间
如果磁盘已经满到系统无法正常运行,你需要先紧急释放空间才能进行后续操作。以下是安全的清理步骤:
第一步,手动删除已经压缩的旧日志文件(.gz、.1、.2等后缀的文件通常可以安全删除):
find /var/log -name "*.gz" -mtime +30 -delete find /var/log -name "*.[0-9]" -mtime +30 -delete
第二步,清空正在写入的大日志文件(注意不要直接删除文件,而是清空内容):
truncate -s 0 /var/log/nginx/access.log truncate -s 0 /var/log/syslog
第三步,清理Docker的过期日志:
find /var/lib/docker/containers -name "*-json.log" -size +100M -exec truncate -s 0 {} \;
制定一套完善的logrotate配置最佳实践
解决了眼前的问题后,你需要建立一套长期有效的日志管理策略。以下是我总结的最佳实践:
1. 全局启用压缩:修改/etc/logrotate.conf,把#compress改成compress,同时加上delaycompress避免正在写入的文件被立即压缩。
2. 根据服务特性设定合理的rotate值:低流量服务保留7-14天,中等流量保留30天,高流量服务保留7天但配合更频繁的轮转(如hourly)。
3. 对所有自定义服务创建独立的logrotate配置:不要依赖全局默认,每个重要服务都应该在/etc/logrotate.d/下有自己的配置文件。
4. 配置postrotate脚本确保服务正确重新打开日志文件:Nginx需要kill -USR1,Apache需要graceful重启,否则新日志会继续写入旧文件。
5. 设置监控告警:用cron配合脚本定期检查/var/log目录大小,超过阈值就发告警。可以写一个简单的检查脚本:
#!/bin/bash
LOG_DIR="/var/log"
THRESHOLD=80
USAGE=$(df $LOG_DIR | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $USAGE -gt $THRESHOLD ]; then
echo "WARNING: $LOG_DIR usage is ${USAGE}%" | mail -s "Disk Space Alert" admin@example.com
fi
6. 定期验证logrotate是否真正在执行:运行logrotate的调试模式查看哪些文件会被轮转:
logrotate -d /etc/logrotate.conf
logrotate配置中常见的参数含义速查
为了方便你日后调整配置,这里把关键参数一次性列出来:daily(每天轮转)、weekly(每周)、monthly(每月)、rotate N(保留N份旧日志)、compress(压缩旧日志)、delaycompress(延迟一轮再压缩)、missingok(日志不存在时不报错)、notifempty(空文件不轮转)、create 权限 用户 组(创建新日志文件的权限和属主)、copytruncate(复制后截断原文件,适用于不能重命名的场景)、sharedscripts(多个日志共享一个postrotate脚本)。理解这些参数的组合使用,你就能针对任何场景写出合适的配置。
总结:从被动救火到主动防控
logrotate配置不当导致磁盘满这个问题,本质上是运维管理中"设置后不管"的典型表现。Debian系统虽然自带了logrotate,但默认配置并不适合所有场景。你需要做的是:部署服务后主动检查并完善日志轮转策略,针对Docker等特殊场景单独处理,建立监控机制提前预警。把这些做到位,磁盘满的问题基本上就不会再找上你了。记住,日志管理不是可有可无的小事,它直接关系到系统的稳定性和可维护性。
