logrotate,别让日志把磁盘撑爆)
Mac 学 Linux 入门(21):logrotate,别让日志把磁盘撑爆摘要:truncate只是「把杯子倒空」,杯子还在接水。这篇讲清 Linux 自带的日志切割工具logrotate:把 Ubuntu 默认的 nginx 配置逐行拆开讲,搞懂daily/rotate/compress/delaycompress/create/sharedscripts/postrotate;再用-d模拟、-f强制切割,亲眼看清.1和.2.gz是怎么排的;最后是日志切割最经典的事故——切完日志 Nginx 还在写旧文件,以及copytruncate为什么只能当备选。文末还加了一条能提前预警的 PromQL。承接上篇:磁盘告警处理完了,truncate把磁盘从 93% 拉回了 75%。一、老周的追问早上到工位,小林把昨晚的磁盘告警处理过程汇报了一遍。老周听完,点了点头,然后问了一个问题:「你昨天truncate了日志,磁盘从 93% 降到 75%。那明天呢?」「明天……日志继续写,继续涨?」「对。」老周说,「**你truncate是『把杯子倒空』,但杯子还在接水。**你今天倒一次,明天它又满了。你得让杯子自动换,而不是手动倒。」「怎么自动换?」「logrotate。」老周说,「Linux 自带的日志切割工具。它按时间或大小,自动把旧日志切走、压缩、保留一定数量、删除更早的。你配好之后,就不用管了。」「那我昨天为什么没想到?」「因为你还没学。」老周说,「今天教你。配完这个,你以后不会再因为日志满磁盘被告警吵醒了。」二、logrotate是什么?「它干四件事:」第一,切割。「把当前日志改名,比如access.log改成access.log.1,然后让 Nginx 重新打开一个新的access.log继续写。」第二,压缩。「旧日志用gzip压缩。access.log.1变成access.log.1.gz。」第三,保留。「只保留最近 N 份,比如 14 份。第 15 份自动删除。」第四,定时。「logrotate由cron或systemd timer定时触发,默认每天跑一次。」「那它怎么知道要切割哪些日志?」「看配置文件。主配置在/etc/logrotate.conf,各个服务的配置在/etc/logrotate.d/下。」ls/etc/logrotate.d/输出:apt bootlog dpkg nginx rsyslog ufw ...「看到了吗?nginx已经有配置文件了。」老周说,「你打开看看。」cat/etc/logrotate.d/nginx输出:/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts prerotate if [ -d /etc/logrotate.d/httpd-prerotate ]; then \ run-parts /etc/logrotate.d/httpd-prerotate; \ fi \ endscript postrotate invoke-rc.d nginx rotate /dev/null 21 endscript }「这是 Ubuntu 默认的 Nginx 日志切割配置。」老周说,「它已经配好了,但你从来没检查过,对不对?」小林脸一红:「我没看过。」「所以你磁盘满了,不是因为没有logrotate,而是因为『你没有验证它到底有没有在跑』。」老周说,「今天你把这份配置搞懂,再验证一遍。」三、logrotate配置详解/var/log/nginx/*.log—— 匹配/var/log/nginx/下所有.log文件。access.log和error.log都会被处理。daily—— 每天切割一次。也可以写weekly、monthly、size 100M。missingok—— 如果日志文件不存在,不报错,继续处理下一个。rotate 14—— 保留 14 份旧日志。第 15 份自动删除。daily+rotate 14,就是保留 14 天。compress—— 压缩旧日志,用gzip。delaycompress—— 延迟压缩。刚切割的日志不立刻压缩,等下一次切割时再压。为什么?因为有些程序切割后还在写旧文件,立刻压缩会报错。notifempty—— 如果日志是空的,不切割。create 0640 www-data adm—— 切割后创建新日志文件,权限0640,属主www-data,属组adm。如果不写create,新日志可能权限不对,Nginx 写不了。sharedscripts—— 多个日志文件,postrotate只执行一次。不写的话,每个日志文件都会执行一次。prerotate ... endscript—— 切割前执行的脚本。postrotate ... endscript—