场景:nginx 日志需要按天切割,期望在次日零点进行切割,现采用 logrotate 来实现。
logrotate 配置如下:
$ cat /etc/logrotate.d/nginx
/data/log/nginx-blog/*.log {
daily
dateyesterday
missingok
rotate 10
compress
delaycompress
notifempty
sharedscripts
postrotate
export KUBECONFIG=/etc/kubernetes/admin.conf
kubectl -n blog exec svc/nginx-php-svc -c nginx -it -- bash -c "kill -USR1 \`cat /var/run/nginx.pid\`"
endscript
}
问题:发现每次都是在凌晨 3 点多执行切割,和我们期望的不符合。
其实 logrotate 的执行计划是由 anacron 控制的,而 anacron 依赖 crond 服务运行。anacron 配置文件路径为 /etc/anacrontab,从配置文件可以看到设置延迟时间和作业启动时间。如下,配置作业会在 3 点 到 22 点这个时间段执行,延迟时间为 delay in minutes + RANDOM_DELAY,实际任务应该会在 3:(05-50) 内执行。
以日方案为例,此时会加载 /etc/cron.daily 目录下的可执行文件并执行,logrotate 就位于这个目录,所以 logrotate 会在会在 3:(05-50) 这个时间段执行。
$ cat /etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
# the maximal random delay added to the base delay of the jobs
RANDOM_DELAY=45 # 随机延迟时间,最大 45 分钟
# the jobs will be started during the following hours only
START_HOURS_RANGE=3-22 # 作业开始时间段
#period in days delay in minutes job-identifier command
1 5 cron.daily nice run-parts /etc/cron.daily # 日方案
7 25 cron.weekly nice run-parts /etc/cron.weekly # 周方案
@monthly 45 cron.monthly nice run-parts /etc/cron.monthly # 月方案
说明:(man anacrontab)
period in days:作业执行频率
delay in minutes:指定 anacron 在执行作业之前等待的分钟数,0 表示没有延迟。
job-identifier:作业标识符
command:执行的命令
修改 /etc/anacrontab,将 cron.daily 任务调整到零点执行。
$ vim /etc/anacrontab # 修改配置
RANDOM_DELAY=0
START_HOURS_RANGE=0-1
1 0 cron.daily nice run-parts /etc/cron.daily
但是通过 cron 日志发现 cron.daily 任务执行有一分钟延迟:
Jul 27 00:00:01 cp CROND[39174]: (root) CMD (/usr/lib64/sa/sa1 1 1)
Jul 27 00:01:01 cp CROND[41530]: (root) CMD (run-parts /etc/cron.hourly)
Jul 27 00:01:01 cp run-parts(/etc/cron.hourly)[41530]: starting 0anacron
Jul 27 00:01:01 cp anacron[41539]: Anacron started on 2023-07-27
Jul 27 00:01:01 cp anacron[41539]: Will run job `cron.daily' in 0 min.
Jul 27 00:01:01 cp anacron[41539]: Will run job `cron.weekly' in 25 min.
Jul 27 00:01:01 cp anacron[41539]: Jobs will be executed sequentially
Jul 27 00:01:01 cp run-parts(/etc/cron.hourly)[41541]: finished 0anacron
Jul 27 00:01:01 cp anacron[41539]: Job `cron.daily' started
Jul 27 00:01:01 cp run-parts(/etc/cron.daily)[41542]: starting logrotate
Jul 27 00:01:02 cp run-parts(/etc/cron.daily)[41577]: finished logrotate
Jul 27 00:01:02 cp run-parts(/etc/cron.daily)[41542]: starting man-db.cron
Jul 27 00:01:02 cp run-parts(/etc/cron.daily)[41604]: finished man-db.cron
Jul 27 00:01:02 cp run-parts(/etc/cron.daily)[41542]: starting mlocate
Jul 27 00:01:04 cp run-parts(/etc/cron.daily)[41648]: finished mlocate
Jul 27 00:01:04 cp anacron[41539]: Job `cron.daily' terminated (produced output)
上面配置文件只是配置 anacron 任务的启动时间和延迟时间,但这要建立在 anacron 运行的情况下,而 anacron 依赖 crond 服务运行,所以这个延迟一分钟大概率是 crond 定时运行 anacron 设置的。
如下,/etc/cron.d/ 目录下 0hourly 文件配置每小时的第一分钟运行 /etc/cron.hourly 目录下所有的可执行文件,anacron 的运行脚本就处于这个目录下。
$ cat /etc/cron.d/0hourly
# Run the hourly jobs
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=root
01 * * * * root run-parts /etc/cron.hourly
[root@cp nginx-blog]# cat /etc/cron.hourly/0anacron
#!/bin/sh
# Check whether 0anacron was run today already
if test -r /var/spool/anacron/cron.daily; then
day=`cat /var/spool/anacron/cron.daily`
fi
if [ `date +%Y%m%d` = "$day" ]; then
exit 0;
fi
# Do not run jobs when on battery power
if test -x /usr/bin/on_ac_power; then
/usr/bin/on_ac_power >/dev/null 2>&1
if test $? -eq 1; then
exit 0
fi
fi
/usr/sbin/anacron -s
anacron 这个服务会被 cron 控制每小时执行一次, anacron 执行前会去检查今天是否运行,依据是对比当前时间和 /var/spool/anacron/cron.daily 记录的时间是否一致。一致退出脚本,不一致运行 anacron。
修改 /etc/cron.d/0hourly,在每小时 0 分运行 anacron:
$ cat /etc/cron.d/0hourly
00 * * * * root run-parts /etc/cron.hourly
查看 cron 日志验证:
Jul 28 00:00:01 cp run-parts(/etc/cron.hourly)[47915]: starting 0anacron
Jul 28 00:00:01 cp run-parts(/etc/cron.hourly)[47933]: finished 0anacron
Jul 28 00:00:01 cp anacron[47931]: Anacron started on 2023-07-28
Jul 28 00:00:01 cp anacron[47931]: Will run job `cron.daily' in 0 min.
Jul 28 00:00:01 cp anacron[47931]: Jobs will be executed sequentially
Jul 28 00:00:01 cp anacron[47931]: Job `cron.daily' started
Jul 28 00:00:01 cp run-parts(/etc/cron.daily)[47935]: starting logrotate
Jul 28 00:00:01 cp run-parts(/etc/cron.daily)[47970]: finished logrotate
Jul 28 00:00:01 cp run-parts(/etc/cron.daily)[47935]: starting man-db.cron
Jul 28 00:00:02 cp run-parts(/etc/cron.daily)[47995]: finished man-db.cron
Jul 28 00:00:02 cp run-parts(/etc/cron.daily)[47935]: starting mlocate
Jul 28 00:00:03 cp run-parts(/etc/cron.daily)[48056]: finished mlocate
Jul 28 00:00:03 cp anacron[47931]: Job `cron.daily' terminated (produced output)
Jul 28 00:00:03 cp anacron[47931]: Normal exit (1 job run)