Ubuntu系统中cron定时任务产生的日志如果不做轮转和清理,/var/log/syslog或者/var/log/cron.log会被持续写入,几个月下来轻松占满几十GB磁盘空间,甚至导致系统分区爆满、服务崩溃。解决这个问题的核心思路就是两步:第一步配置logrotate对cron相关日志做自动轮转压缩,第二步通过cron自身的定时清理任务把过期日志删掉。下面我把完整操作一步一步讲清楚。
一、先搞清楚Ubuntu上cron日志存在哪里
Ubuntu默认使用的是cron守护进程(cron daemon),它的运行日志通常记录在/var/log/syslog里面,而不是像CentOS那样有独立的/var/log/cron文件。你可以用下面的命令确认一下:
grep CRON /var/log/syslog | tail -20
如果你安装了rsyslog并且做了单独的cron日志分离配置,那日志可能在/var/log/cron.log。不管在哪里,处理方式都是一样的,就是用logrotate来管。
二、配置logrotate实现cron日志自动轮转
logrotate是Ubuntu自带的日志轮转工具,配置文件放在/etc/logrotate.d/目录下。系统已经有一个syslog的轮转配置,但我们需要确认它对cron相关日志的处理是否到位。打开配置文件看看:
cat /etc/logrotate.d/rsyslog
如果你的cron日志混在syslog里,这个文件里的规则就会生效。默认情况下它是按周轮转、保留4周、压缩旧日志。如果你觉得不够,可以单独为cron日志建一个配置文件:
sudo nano /etc/logrotate.d/cron
写入以下内容:
/var/log/syslog {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 syslog adm
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
/var/log/cron.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 0640 syslog adm
sharedscripts
}这段配置的意思是:每天轮转一次,保留30份,压缩旧文件(delaycompress表示延迟一天再压缩,防止正在写入的文件被压缩),文件不存在也不报错(missingok),空文件不轮转(notifempty)。你根据自己的磁盘情况调整rotate的数值,磁盘小就改成14或者7。
三、手动测试logrotate是否正常工作
配置写好之后别直接等,先手动跑一次看看效果:
sudo logrotate -f /etc/logrotate.d/cron
加上-f参数是强制执行,不管时间到没到。执行完之后去/var/log/目录下看看,应该能看到syslog.1、syslog.2.gz这类文件。如果报错,根据提示信息排查权限或者路径问题。
四、用cron自身清理过期日志文件
logrotate负责轮转和压缩,但它不会自动删除很久以前的压缩包。你需要再加一个清理任务。编辑root的crontab:
sudo crontab -e
在文件末尾加上这一行:
0 3 * * 0 find /var/log -name "*.gz" -mtime +60 -delete
这条命令的含义是:每周日凌晨3点,查找/var/log目录下修改时间超过60天的.gz压缩日志文件并删除。你也可以更精细一点,只清理cron相关的:
0 3 * * 0 find /var/log -name "syslog*" -mtime +30 -delete 0 3 * * 0 find /var/log -name "cron*" -mtime +30 -delete
注意-mtime +30表示30天前的文件,这个数值根据你的业务需求调整。如果你的日志轮转保留30份,那清理60天前的比较安全,给自己留一个月的缓冲。
五、检查cron任务本身的输出是否也在制造垃圾
很多人忽略了一个问题:cron任务执行时如果有输出(stdout和stderr),系统默认会通过邮件发给用户。如果没配置邮件服务,这些邮件会堆积在/var/mail/或者/var/spool/mail/里。解决办法有两个:
第一,在crontab里把任务输出重定向到/dev/null:
0 2 * * * /path/to/script.sh > /dev/null 2>&1
第二,如果你确实需要保留任务输出用于排查问题,那就重定向到一个专门的日志文件,然后让logrotate也管这个文件:
0 2 * * * /path/to/script.sh >> /var/log/mycron/task.log 2>&1
然后在/etc/logrotate.d/里给/var/log/mycron/task.log也加上轮转规则。
六、监控磁盘使用情况,设置告警
光做轮转和清理还不够,你得有监控。可以写一个简单的shell脚本,检查/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: /var/log usage is ${USAGE}%" | mail -s "Disk Alert" admin@example.com
fi把这个脚本放到/usr/local/bin/check_log_disk.sh,给执行权限,然后加入cron每天跑一次:
0 8 * * * /usr/local/bin/check_log_disk.sh
七、一些容易踩的坑和实战经验
第一,logrotate配置里的路径一定要写对。如果你的cron日志在/var/log/syslog而不是/var/log/cron.log,那你配/var/log/cron.log的规则是不会生效的。先用ls -l /var/log/确认实际路径。
第二,不要同时让logrotate和cron的find命令清理同一批文件,容易产生竞争。建议logrotate负责轮转保留N天,cron清理任务负责删掉超过N天的,两者配合但不重叠。
第三,如果你用的是systemd的timers替代了cron(Ubuntu 18.04以后部分场景会用),那日志轮转的逻辑一样,但清理任务要写在systemd timer对应的service里或者单独的cron里。
第四,压缩后的.gz文件虽然小,但如果积累太多,inode也会被占满。所以定期清理不只是清空间,也是清inode。用find -delete的时候注意别误删了正在使用的文件,delaycompress就是为了解决这个问题。
第五,如果你的服务器跑了大量cron任务,比如每分钟都有任务在跑,那日志增长速度会非常快。这种情况下建议把日志轮转频率改成hourly(每小时),同时清理周期缩短到15天。
八、总结操作清单
把上面的内容浓缩成一个操作清单,你照着做就行:1、确认cron日志的实际存放路径;2、在/etc/logrotate.d/下创建或修改cron相关的轮转配置;3、用logrotate -f手动测试一次;4、在crontab里加上find清理过期压缩包的任务;5、把cron任务的输出重定向,避免邮件堆积;6、加一个磁盘监控脚本做兜底。这套组合拳打下来,Ubuntu的cron日志问题基本就解决了,磁盘不会再被日志撑爆。
