场景: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)

发表评论

验证码: 30 − 23 =