Cron.daily和cron.hourly不执行排查随记

来自三线的随记

环境+现象简述

Red Hat Enterprise Linux release 8.2 (Ootpa)

(Redhat系如centos其实都类似实现)


接报障称/var/log下的日志文件占用空间大导致触发了磁盘空间告警,登陆节点检查发现日志在4月3号后应该就没有再切割过

TL;DR

在Redhat系发行版(CentOS Linux/Redhat Linux/Oracle Linux/...)系统下,cron.dailycron.weeklycron.monthly 下的配置文件的执行是由anacron 组件实现的,而 anacron 的被调用执行又是由 crontabcron.hourly/0anacron 实现的

每小时调用一次anacron判断是否需要执行每日或者每周或者每月任务(所以利用原生logrotate配置对nginx日志进行切割,如果发现实际切割时间与零点偏移过大的话也是anacron的配置问题)

注意/etc/cron.hourly/0anacron文件需要可执行权限,不然 run-parts 不会去执行(可以通过 run-parts --test 参数测试确认,部分发行版系统下run-parts执行的文件甚至不能有扩展名)

cron.hourly 的被调用是在 /etc/cron.d/0hourly 中定义的


小插曲:

虽然随后我与当下大热的打工人作弊神器——ChatGPT交流后,ChatGPT告诉我:

anacron守护进程是一个长期运行的程序,它负责管理和协调anacron定时任务的执行。在Linux系统中,anacron守护进程通常是由系统服务管理器(如systemd)启动并运行的。

anacron守护进程的主要作用是检查上一次执行任务的时间戳,并根据每个定时任务的日期和时间来确定哪些任务需要执行,然后在系统处于闲置状态时调度这些任务,并记录任务执行的结果。通过启动anacron守护进程,我们可以确保在系统遇到意外关机或定时任务被跳过的情况下,任务仍然会在后续的闲置时间内得到执行。

通常,anacron守护进程还允许管理员配置每个任务的优先级,以便确保任务的执行顺序。

这与我的排查结论有一定的出入,应该是有不同的发行版系统存在不同的行为

排查过程

首先先检查确认logrotate配置没问题

/usr/sbin/logrotate /etc/logrotate.conf -d

回显没有明确的问题

由于logrotate默认属于没有守护进程的实现,需要依赖crontab去调用

确认logrotate的被调用配置文件存在和crontab的状态:

[root@prdmgtr01 cron.d]# ls /etc/cron.daily/ -l
total 12
-rwx------. 1 root root 219 Apr  1  2020 logrotate
-rwxr-xr-x. 1 root root 618 Oct 30  2018 man-db.cron
-rwx------. 1 root root 558 May 18  2022 rhsmd
systemctl status crond
journalctl -u crond

确认crontab的守护进程正常,但是在输出的日志刚好发现crontab执行记录有问题

root@prdmgtr01:/etc/cron.daily >journalctl -u crond -n 15
-- Logs begin at Sun 2023-03-19 01:49:01 GMT, end at Sun 2023-04-16 14:56:19 IST. --
Apr 03 06:01:01 prdmgtr01 CROND[2411696]: (root) CMD (run-parts /etc/cron.hourly)
Apr 03 07:01:01 prdmgtr01 CROND[2549785]: (root) CMD (run-parts /etc/cron.hourly)
Apr 03 08:01:01 prdmgtr01 CROND[2687939]: (root) CMD (run-parts /etc/cron.hourly)
Apr 03 09:01:01 prdmgtr01 CROND[2825903]: (root) CMD (run-parts /etc/cron.hourly)
Apr 03 10:01:01 prdmgtr01 CROND[2964144]: (root) CMD (run-parts /etc/cron.hourly)
Apr 03 11:01:01 prdmgtr01 CROND[3102130]: (root) CMD (run-parts /etc/cron.hourly)
Apr 09 01:00:01 prdmgtr01 CROND[445672]: (root) CMD (/usr/sbin/raid-check)
Apr 16 01:00:01 prdmgtr01 CROND[1962505]: (root) CMD (/usr/sbin/raid-check)

从这就可以看出来自Apr 03以后cron.hourly就没有再被执行过

root@prdmgtr01:/etc/cron.daily >journalctl -u crond --since 2023-04-01|grep daily
Apr 01 03:01:01 prdmgtr01 anacron[3757301]: Will run job `cron.daily' in 6 min.
Apr 01 03:07:01 prdmgtr01 anacron[3757301]: Job `cron.daily' started
Apr 01 03:07:01 prdmgtr01 anacron[3757301]: Job `cron.daily' terminated (produced output)
Apr 02 03:01:01 prdmgtr01 anacron[2876968]: Will run job `cron.daily' in 28 min.
Apr 02 03:29:01 prdmgtr01 anacron[2876968]: Job `cron.daily' started
Apr 02 03:29:01 prdmgtr01 anacron[2876968]: Job `cron.daily' terminated (produced output)
Apr 03 03:01:01 prdmgtr01 anacron[1997420]: Will run job `cron.daily' in 30 min.
Apr 03 03:31:01 prdmgtr01 anacron[1997420]: Job `cron.daily' started
Apr 03 03:31:02 prdmgtr01 anacron[1997420]: Job `cron.daily' terminated (produced output)
root@prdmgtr01:/etc/cron.daily >date
Sun Apr 16 14:57:52 IST 2023

同样的cron.daily在Apr 03以后也没有再被执行过

问题定位方向大致清晰,就是cron.daily没有被按天执行导致logrotate不被执行

顺手查一下cron.daily下面的文件定义有没有异常

root@prdmgtr01:/etc/cron.daily >run-parts --test /etc/cron.daily
/etc/cron.daily/logrotate
root@prdmgtr01:/etc/cron.daily >ls -l /etc/cron.daily
total 4
-rwxr-xr-x. 1 root root 189 Jan  4  2018 logrotate

cron.daily按天执行是由anacron实现的

[root@prdmgtr01 cron.d]# 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
# 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

确认anacron包没有被人误删

[root@prdmgtr01 root]# rpm -qa|grep anacron
cronie-anacron-1.4.11-23.el7.x86_64

检查配置文件发现 /etc/cron.hourly/0anacron 被人误删了

原本应该有如下文件在节点上负责每小时执行一次0anacron,所以这个就是为什么cron.daily下面的配置例如logrotate没有每天执行的原因之一

[root@prdmgtr01 cron.hourly]# ls -l /etc/cron.hourly/
total 4
-rwxr-xr-x. 1 root root 392 Aug  9  2019 0anacron
[root@prdmgtr01 cron.hourly]# 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 s参数的作用如下,记录一下,不做深入讨论:

[root@prdmgtr01 cron.hourly]# /usr/sbin/anacron -h
Usage:
 anacron [options] [job] ...
 anacron -T [-t anacrontab-file]

Options:
 -s         Serialize execution of jobs
 -f         Force execution of jobs, even before their time
 -n         Run jobs with no delay, implies -s
 -d         Don't fork to the background
 -q         Suppress stderr messages, only applicable with -d
 -u         Update the timestamps without actually running anything
 -V         Print version information
 -h         Print this message
 -t <file>  Use alternative anacrontab
 -T         Test an anacrontab
 -S <dir>   Select a different spool directory

See the anacron(8) manpage for more details.

至于cron.hourly下的文件定义同样没有被每小时执行的原因也是因为 /etc/cron.d/0hourly 配置文件被删了

原本应该有如下文件定义

[root@prdmgtr01 cron.d]# ls -l /etc/cron.d
total 8
-rw-r--r--. 1 root root 128 Aug  9  2019 0hourly
-rw-------. 1 root root 235 Apr  1  2020 sysstat
[root@prdmgtr01 cron.d]# 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

PS: sar的性能采集间隔(默认十分钟)也是在这里定义的

[root@prdmgtr01 cron.d]# cat /etc/cron.d/sysstat
# Run system activity accounting tool every 10 minutes
*/10 * * * * root /usr/lib64/sa/sa1 1 1
# 0 * * * * root /usr/lib64/sa/sa1 600 6 &
# Generate a daily summary of process accounting at 23:53
53 23 * * * root /usr/lib64/sa/sa2 -A

最终补回原本应有的 /etc/cron.hourly/0anacron/etc/cron.d/0hourly 配置即恢复正常工作,注意0anacron文件需要可执行权限,不然 run-parts 不会去执行(可以通过 run-parts --test 参数测试确认)

参考资料:

  1. man crontabs
  2. run-parts 相关特性
  3. logrotate自定义切割时间的一些坑/为什么logrotate没有在零点准时执行