cron 是一个在后台运行调度的守护进程,而 crontab 是一个设置 cron 的工具。

本文总结一下笔者使用 crontab 过程中常遇到的问题和一些经验技巧,希望可以帮助到大家。

1. 安装 cron 服务

安装服务

# Debian/Ubuntu 系统
sudo apt-get install cron
# CentOS/RHEL 系统中
sudo yum install cronie

开机自启

# Debian/Ubuntu 系统
sudo systemctl start cron
sudo systemctl enable cron
# CentOS/RHEL 系统中
sudo systemctl start crond
sudo systemctl enable crond

管理任务

crontab -e   # 编辑当前用户的 crontab 任务列表
crontab -l   # 列出当前用户的 crontab 任务列表
crontab -r   # 移除当前用户的 crontab 任务列表

2. 定义配置文件

所有用户定义的 crontab 文件都被保存在 /var/spool/cron/crontabs 目录中。其文件名与用户名一致。

# /var/spool/cron/crontabs/root
* * * * * /opt/scripts/docker_health_check.sh > /dev/null 2>&1
* * * * * docker exec web /bin/sh -c  "/usr/local/bin/php /var/www/html/check.php >> /dev/null 2>&1"

3. 查看执行日志

使用 journalctl -u cron.service 查看

使用 tail -f /var/log/cron.log 查看日志

debian 默认没有开启 crontab 的日志,以下步骤开启 crontab 的日志。

  • 确保 rsyslog 服务正在运行
# 安装服务
sudo apt install rsyslog
# 启动服务
sudo systemctl start rsyslog
sudo systemctl enable rsyslog
sudo systemctl status rsyslog  # 检查状态
  • 检查 rsyslog 配置,确保 /etc/rsyslog.conf 中包含了生成 syslog 的配置行
# cat /etc/rsyslog.conf
# 修改 #cron.* /var/log/cron.log这一行
# 删除 #
sed -i 's/#cron\.\*/cron\.\*/g' /etc/rsyslog.conf
# 重启服务
/etc/init.d/rsyslog restart
# 查看日志
tail -f -n100 /var/log/cron.log

4. 实现秒级定时任务

crontab 的粒度最小是到分钟,但是我们还是可以通过变通的方法做到隔多少秒运行一次。

传统暴力法

# 每 10 秒执行一次
* * * * * /usr/bin/ping -c 1 8.8.8.8
* * * * * sleep 10; /usr/bin/ping -c 1 8.8.8.8
* * * * * sleep 20; /usr/bin/ping -c 1 8.8.8.8
* * * * * sleep 30; /usr/bin/ping -c 1 8.8.8.8
* * * * * sleep 40; /usr/bin/ping -c 1 8.8.8.8
* * * * * sleep 50; /usr/bin/ping -c 1 8.8.8.8

但如果 2 秒要执行一次,就要写 30 条,这样实在是太不优雅了。所以采用 shell 脚本实现如下

#!/bin/bash
# * * * * * /opt/scripts/crontab.sh
step=2 # 间隔的秒数,不能大于 60
for (( i = 0; i < 60; i=(i+step) )); do
  $(date -R >> /var/log/crontab.log) # 执行脚本
  sleep $step
done
exit 0

添加执行任务,查看日志可以看到,实现了每 2 秒将系统时间写入文件

* * * * * /opt/scripts/crontab.sh

5. Docker 定时任务最佳方式

Docker 环境下,在主机和在容器中使用 cron 执行定时任务,大概有以下三种方式:

  • 使用主机的 cron 实现定时任务
  • 创建一个新容器专门执行定时任务
  • 在原有容器上安装 cron,里面运行“服务 + cron” 2 个进程

最佳的方式应该是方式1,因为它最为简单。在主机中的 crontab -e 中可以:

* * * * * docker exec web /bin/sh -c  "/usr/local/bin/php /var/www/html/check.php >> /dev/null 2>&1"

注意:这里 docker 命令不需要加 -it,因为加 -it 就要开启了一个终端,而计划任务是无法进入任何终端。

6. Docker 构建和定义定时任务

FROM php:8.3.2-fpm-alpine3.18
# Install cron
RUN apk add --no-cache dcron
# Crontab
COPY deploy/cronjobs /etc/cron.d/cronjobs
RUN dos2unix /etc/cron.d/cronjobs
RUN /usr/bin/crontab /etc/cron.d/cronjobs
RUN chmod 0644 /etc/cron.d/cronjobs && mkdir /var/log/cron

其中 /etc/cron.d/cronjobs 文件内容

# /etc/cron.d/cronjobs
# Run the scripts every minute
* * * * * echo "this is crontab" $(date +%Y-%m-%d" "%H:%M:%S) >> /var/log/crontab_output.log 2>&1

以上,通过定义 /etc/cron.d/cronjobs 配置文件,从而实现构建启动后具自动执行指定脚本的镜像。

7. 在线工具

crontab 的辅助工具很多,下面是用过多款工具后收藏至今的两款。两者都可以直观的查看指定计划后,下次执行的时间点,从而检查设置是否有误。

  • https://tool.lu/crontab/ 推荐 tool.lu 是因为它是中文界面
  • https://crontab.guru/ 更好用和推荐的是 crontab.guru,界面简单明了,而且用户可以通过随机和内置的70个示例,了解 crontab 的使用方法。