logrotate 日志轮转实战:别让日志把磁盘悄悄撑满
很多服务器出故障,原因并不复杂:某个服务日志一直往同一个文件里写,几个月后磁盘被占满,数据库写不进去、服务起不来,SSH 登录都变慢。Linux 自带的 logrotate 就是专门解决这个问题的工具。这篇文章从配置结构讲起,结合一个自定义应用的例子,把轮转、压缩、保留天数和排查方法整理成一份可以直接照着做的清单。
一、logrotate 是怎么被触发的
logrotate 本身不是常驻进程,而是由定时任务每天调用一次。在多数发行版上可以这样确认:
systemctl list-timers | grep logrotate # systemd timer 方式
ls /etc/cron.daily/ | grep logrotate # cron 方式
主配置文件是 /etc/logrotate.conf,里面通常有一行 include /etc/logrotate.d,各个软件包把自己的规则放进 /etc/logrotate.d/ 目录。我们给自己的应用加规则,也推荐放在这个目录里,而不是改主配置。
二、先看懂一条完整规则
假设应用日志写在 /var/log/myapp/ 下,新建 /etc/logrotate.d/myapp:
/var/log/myapp/*.log {
daily
rotate 14
missingok
notifempty
compress
delaycompress
dateext
dateformat -%Y%m%d
create 0640 myapp myapp
sharedscripts
postrotate
systemctl kill -s USR1 myapp.service >/dev/null 2>&1 || true
endscript
}
逐项解释:
daily:每天轮转一次,也可以用weekly、monthly,或者配合size 100M按大小轮转。rotate 14:保留 14 份旧日志,超过的自动删除,这是控制磁盘占用的关键。missingok/notifempty:文件不存在不报错,文件为空不轮转。compress+delaycompress:旧日志用 gzip 压缩,但最近一份先不压,方便直接tail查看,也避免进程还在写时被压缩。dateext:用日期做后缀,比.1 .2 .3更直观。create 0640 myapp myapp:轮转后新建空文件,并指定权限和属主,防止服务因为没权限写日志而报错。sharedscripts+postrotate:所有文件轮转完只执行一次脚本,通知应用重新打开日志文件。
三、copytruncate 和 postrotate 怎么选
轮转的本质是把旧文件改名。问题在于,进程持有的是文件描述符,改名后它会继续往旧文件里写。处理方式有两种:
- 通知进程重新打开日志:Nginx 发
USR1信号,很多服务支持reload。这是首选方式,不丢日志。 - copytruncate:先复制一份,再把原文件清空。适合不支持重新打开日志的程序,但复制和清空之间写入的内容可能丢失,大文件复制也比较耗 IO。
经验是:能用信号就用信号,实在不行才用 copytruncate。
四、上线前一定要先演练
规则写好后不要等到第二天才看结果,先用调试模式检查语法和执行计划:
logrotate -d /etc/logrotate.d/myapp
-d 只打印将要做的动作,不会真的改文件。确认无误后可以强制执行一次:
logrotate -vf /etc/logrotate.d/myapp
ls -lh /var/log/myapp/
如果看到带日期后缀的旧文件和新的空日志文件,并且应用还在正常写入,说明配置生效。
五、常见坑和排查思路
- 规则没生效:查看状态文件
/var/lib/logrotate/status(部分系统在/var/lib/logrotate.status),里面记录了每个文件上次轮转的时间。logrotate 依据它判断是否“到期”,手动改过时间可能导致当天不轮转。 - 报 parent directory has insecure permissions:日志目录对组或其他用户可写时会出现,加上
su myapp myapp指定以哪个用户身份轮转即可。 - 磁盘还是满:用
lsof +L1查看已删除但仍被进程占用的文件。日志删了空间没释放,通常就是进程没重新打开日志。 - 容器里的日志:Docker 默认的 json-file 日志不归 logrotate 管,应在
/etc/docker/daemon.json里配置"log-opts": {"max-size": "50m", "max-file": "3"}。
六、小结
一套稳妥的日志策略可以概括为三点:按时间或大小定期轮转,压缩并限制保留份数,轮转后让进程重新打开日志。花十分钟写好一条 logrotate 规则,再用 -d 演练一遍,就能避免很多“半夜磁盘告警”的情况。建议给每台新服务器的自定义服务都顺手加上这样一条规则,并把 df -h 纳入日常巡检。
- 点赞
- 收藏
- 关注作者
评论(0)