在Debian系统运维中,日志文件无限制增长是导致磁盘空间耗尽的头号杀手。要同时保证磁盘空间充足和日志可回溯,核心策略就是配置logrotate实现自动轮替、压缩归档,并结合合理的保留策略与监控告警。具体做法是:编辑/etc/logrotate.conf全局配置和/etc/logrotate.d/下的各服务独立配置文件,设定按天或按周轮转、保留最近N份、压缩旧日志、配合find命令清理超期文件,再用df和du命令定期监控,最后通过cron和监控脚本实现自动化闭环。下面我把每一步拆开讲透。
一、为什么Debian默认日志策略不够用
Debian自带的logrotate工具虽然已经在工作,但默认配置非常保守。以/var/log/syslog为例,默认只保留7份轮转文件,每份不压缩,如果你的系统日志量大,一周就能吃掉几百兆。更麻烦的是,很多第三方服务(Nginx、MySQL、Docker)自己写日志到/var/log下的独立文件,这些文件根本不在默认logrotate管理范围内,会一直涨到把分区撑爆。所以你必须主动介入,针对每类日志制定明确的轮替规则。
二、logrotate核心配置文件结构详解
logrotate的配置分两层:全局配置文件/etc/logrotate.conf控制默认行为,/etc/logrotate.d/目录下每个文件对应一个具体服务或日志路径。你改全局配置会影响所有日志,改单独文件只影响对应服务。建议以单独文件为主,全局只设兜底参数。
先看全局配置文件的关键参数含义:
# /etc/logrotate.conf 关键项解读 weekly # 默认轮转周期:每周 rotate 4 # 默认保留份数:4份 create # 轮转后创建新空文件,权限0644 dateext # 用日期作为后缀而非数字 compress # 启用gzip压缩 delaycompress # 延迟一轮再压缩(方便排查最新一份) missingok # 日志不存在不报错 notifempty # 空文件不轮转
这些默认值对大多数场景偏宽松,你需要根据实际情况收紧。比如把rotate改成12保留三个月,或者改成daily每天轮转适合高流量服务。
三、针对不同日志类型制定具体轮替策略
1. 系统核心日志(syslog、auth.log、kern.log)
这些是Debian最基础的日志,默认已被管理,但建议强化。创建或编辑/etc/logrotate.d/rsyslog:
/var/log/syslog
/var/log/auth.log
/var/log/kern.log
{
daily
rotate 30
compress
delaycompress
missingok
notifempty
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
这里daily表示每天轮转,rotate 30保留30份也就是一个月。postrotate里调用rsyslog-rotate是为了通知rsyslog重新打开日志文件,否则新日志会写入被重命名的旧文件。这个细节很多人忽略,导致日志丢失。
2. Nginx访问日志和错误日志
Nginx日志增长极快,尤其是高并发站点。创建/etc/logrotate.d/nginx:
/var/log/nginx/access.log
/var/log/nginx/error.log
{
daily
rotate 60
compress
delaycompress
missingok
notifempty
sharedscripts
postrotate
[ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
endscript
}
注意这里用kill -USR1而不是reload,因为USR1信号会让Nginx重新打开日志文件,这是Nginx官方推荐的方式。rotate 60保留60天,适合需要回溯两个月访问记录的场景。如果磁盘紧张,可以改成rotate 30并加上size参数。
3. MySQL/MariaDB慢查询日志和通用日志
数据库日志往往体积巨大。创建/etc/logrotate.d/mysql:
/var/log/mysql/slow-query.log
/var/log/mysql/error.log
{
daily
rotate 14
compress
delaycompress
missingok
notifempty
size 500M
postrotate
if [ -f /var/run/mysqld/mysqld.pid ]; then
kill -HUP $(cat /var/run/mysqld/mysqld.pid)
fi
endscript
}
这里加了size 500M,意思是即使没到一天,文件超过500M也会触发轮转。这是双保险机制,防止单日暴增撑爆磁盘。kill -HUP是MySQL重新打开日志文件的信号。
4. Docker容器日志
Docker的json-file日志驱动会在/var/lib/docker/containers/下生成大量json日志。这些不在logrotate默认管理范围内。你需要在/etc/logrotate.d/下创建docker配置,或者更推荐的做法是在daemon.json里设置日志驱动的max-size和max-file参数:
{
"log-driver": "json-file",
"log-opts": {
"max-size": "100m",
"max-file": "5"
}
}
这样每个容器最多保留5个100M的日志文件,总计500M,从源头控制增长。同时再用logrotate做二次兜底。
四、压缩策略与保留周期的平衡艺术
压缩是节省空间最直接的手段。gzip通常能把文本日志压缩到原来的10%-20%。但压缩也有代价:回溯时需要zcat或zless查看,稍微麻烦一点。我的建议是:最近7天的日志不压缩(delaycompress实现),方便实时排查;7天之前的全部压缩。保留周期根据业务需求定,一般系统日志保留30-90天,业务访问日志保留60-180天,审计类日志按合规要求可能要保留一年以上。
如果你需要超长期归档,可以在logrotate的postrotate里加一步把旧日志rsync到远程存储或NAS:
postrotate
/usr/lib/rsyslog/rsyslog-rotate
rsync -az /var/log/syslog.2.gz /backup/logs/$(hostname)/
endscript
这样本地只保留近期日志,历史数据安全转移到别处,既省空间又保证可回溯。
五、用find命令清理超期归档日志
logrotate的rotate参数只能控制份数,但如果你需要按时间清理(比如超过90天的全部删除),就需要配合find命令。写一个清理脚本放到/usr/local/bin/cleanup-old-logs.sh:
#!/bin/bash # 清理/var/log下超过90天的.gz压缩日志 find /var/log -name "*.gz" -type f -mtime +90 -delete # 清理/var/log下超过180天的未压缩日志 find /var/log -name "*.log" -type f -mtime +180 -delete # 清理docker旧日志 find /var/lib/docker/containers -name "*.log" -type f -mtime +30 -delete
然后加到crontab每天凌晨3点执行:
0 3 * * * /usr/local/bin/cleanup-old-logs.sh >> /var/log/cleanup.log 2>&1
六、磁盘空间监控与告警机制
光有轮替还不够,必须有监控。最简单的方式是写一个shell脚本检测关键分区使用率:
#!/bin/bash
THRESHOLD=85
USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
echo "WARNING: / partition usage is ${USAGE}%" | \
mail -s "Disk Space Alert on $(hostname)" admin@example.com
fi
把这个脚本放进cron每小时跑一次。如果你用了Prometheus+node_exporter或者Zabbix,也可以直接配置磁盘使用率告警规则,阈值设80%或85%。关键是要在空间真正耗尽之前收到通知,给你留出处理时间。
七、实战中的常见坑和避坑指南
第一,不要同时设置daily和weekly,logrotate会以最后一个为准,容易混乱。第二,postrotate脚本里的命令必须确保能正确通知服务重新打开日志,否则日志会断。第三,compress和delaycompress不要同时和nocompress混用,逻辑会冲突。第四,如果你用了journald(systemd日志),它有自己的日志管理机制,配置在/etc/systemd/journald.conf里,设置SystemMaxUse和MaxRetentionSec来控制,不要和logrotate重复管理同一份日志。第五,轮转后的旧文件如果权限不对,可能导致后续压缩失败,确保create参数设置了正确的umask或owner。
八、完整方案总结:一套可直接落地的配置清单
把上面所有策略整合起来,你的Debian运维日志管理应该做到以下几点:第一,所有日志路径都有对应的logrotate配置文件,没有遗漏;第二,核心日志daily轮转保留30份,压缩延迟一轮;第三,高增长日志加size限制双保险;第四,Docker从驱动层限制单容器日志量;第五,超期日志用find脚本定期清理;第六,磁盘使用率监控每小时检查一次,超阈值告警;第七,重要日志同步到远程备份保证长期可回溯。做到这七点,磁盘空间问题基本不会再找上你,同时任何时候需要查历史日志都能快速定位。
最后多说一句,日志轮替不是设一次就完事的。业务增长会让日志量变化,你至少每个季度review一次配置,根据实际磁盘使用情况调整rotate份数和保留天数。运维的本质就是持续优化,没有一劳永逸的方案,只有不断迭代的策略。
