使用 at、cron 和 systemd 定时器调度任务

LinuxBeginner
立即练习

介绍

Linux 管理员可以通过多种方式调度任务。at 命令用于调度一次性任务;cron 用于根据简单的时间字段调度周期性任务;而 systemd 定时器则利用 systemd 的依赖关系和日志模型来调度 systemd 服务。

在本实验中,你将创建一个命令脚本,并分别通过这三种方式进行调度。你将检查调度程序服务、排队一个一次性的 at 任务、配置一个 cron 插入式(drop-in)文件、创建一个 systemd 服务与定时器对,并手动测试定时器背后的服务。

检查调度程序并创建任务脚本

在此步骤中,你将确认调度程序服务正在运行,并创建一个供所有调度任务调用的脚本。

进入项目目录。

cd /home/labex/project

检查一次性任务守护进程和 cron 守护进程。当服务正在运行时,systemctl is-active 会输出 active。

systemctl is-active atd crond

列出现有的 systemd 定时器。输出内容显示了下一次运行时间、定时器单元以及它所激活的服务单元。

systemctl list-timers --all --no-pager | sed -n '1,10p'

创建一个脚本,将带有时间戳的行追加到日志文件中。第一个参数 $1 将作为标识哪个调度程序运行了该脚本的标签。

cat > /home/labex/project/scheduled-note.sh <<'EOF'
#!/bin/bash
echo "$(date '+%F %T') $1" >> /home/labex/project/schedule-events.log
EOF

使脚本具有可执行权限。

chmod 755 /home/labex/project/scheduled-note.sh

手动运行一次该脚本。

/home/labex/project/scheduled-note.sh manual-run
tail -n 1 /home/labex/project/schedule-events.log

日志行的末尾应显示 manual-run。

排队一次性 at 任务

在此步骤中,你将使用 at 调度一个一次性任务。这对于需要在未来某个时间点执行一次的工作(例如临时维护任务)非常有用。

将脚本排队,使其在两小时后运行。要运行的命令通过管道传递给 at。

echo "/home/labex/project/scheduled-note.sh at-job" | at now + 2 hours

列出已排队的任务。

atq

保存第一个 atq 行中的任务 ID。任务 ID 是输出中的第一个字段。

job_id="$(atq | awk 'NR==1 {print $1}')"
echo "$job_id" > /home/labex/project/at-job.id
cat /home/labex/project/at-job.id

检查已排队任务的内容。at -c 会打印生成的任务脚本;最后几行应包含你所排队的命令。

at -c "$job_id" | tail -n 12

配置 cron 插入式文件

在此步骤中,你将通过 /etc/cron.d 中的文件配置一个周期性的 cron 任务。该目录下的文件包含一个用户字段,因此系统知道应该以哪个账户运行该命令。

创建一个 cron 文件,以 labex 用户身份每分钟运行一次该脚本。PATH 行确保 cron 拥有可预测的命令搜索路径。

sudo tee /etc/cron.d/rhcsa-schedule-demo >/dev/null <<'EOF'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
* * * * * labex /home/labex/project/scheduled-note.sh cron-job
EOF

将文件模式设置为 644。Cron 文件必须可读,且不应允许普通用户写入。

sudo chmod 644 /etc/cron.d/rhcsa-schedule-demo

重新加载 crond 以使其立即识别该文件。

sudo systemctl reload crond

检查你创建的文件。

sudo cat /etc/cron.d/rhcsa-schedule-demo

调度字段 * * * * * 表示每分钟执行一次。

创建 systemd 服务和定时器

在此步骤中,你将创建一个 systemd 服务以及一个激活该服务的定时器。定时器不会直接运行命令,而是启动一个服务单元。

系统服务应从系统可执行路径执行命令,而不是从用户的工作目录。将脚本的副本安装到 /usr/local/bin 下。

sudo install -m 755 /home/labex/project/scheduled-note.sh /usr/local/bin/rhcsa-scheduled-note
sudo restorecon /usr/local/bin/rhcsa-scheduled-note 2>/dev/null || true
ls -l /usr/local/bin/rhcsa-scheduled-note

创建服务单元。对于运行后即退出的命令,Type=oneshot 是合适的选择。

sudo tee /etc/systemd/system/rhcsa-schedule-demo.service >/dev/null <<'EOF'
[Unit]
Description=Write RHCSA schedule demo entry

[Service]
Type=oneshot
User=labex
ExecStart=/usr/local/bin/rhcsa-scheduled-note timer-job
EOF

创建定时器单元。OnBootSec=2min 设置开机后首次运行的时间,OnUnitActiveSec=5min 设置后续运行相对于上一次激活的时间间隔。

sudo tee /etc/systemd/system/rhcsa-schedule-demo.timer >/dev/null <<'EOF'
[Unit]
Description=Run RHCSA schedule demo periodically

[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Unit=rhcsa-schedule-demo.service

[Install]
WantedBy=timers.target
EOF

重新加载 systemd,启用定时器以实现开机自启,并立即启动它。将 enable 和 start 分开执行,可以清楚地分辨出哪个命令使定时器持久化,哪个命令使其立即生效。

sudo systemctl daemon-reload
sudo systemctl enable rhcsa-schedule-demo.timer
sudo systemctl start rhcsa-schedule-demo.timer

检查定时器。

systemctl list-timers rhcsa-schedule-demo.timer --all --no-pager

定时器应出现在列表中,并且它应该会激活 rhcsa-schedule-demo.service。

测试定时器服务并移除 at 任务

在此步骤中,你将手动启动定时器所使用的服务。这可以立即验证命令,而无需等待下一次定时器触发。你还将移除已排队的 at 任务,因为它仅用于练习。

手动启动服务。

sudo systemctl start rhcsa-schedule-demo.service

检查日志。

tail -n 5 /home/labex/project/schedule-events.log

其中一行应以 timer-job 结尾。

使用之前保存的任务 ID 移除已排队的 at 任务。

job_id="$(cat /home/labex/project/at-job.id)"
atrm "$job_id"

确认任务已不再排队。

atq

总结

你练习了三种调度方法。你检查了 atd、crond 和 systemd 定时器,创建了一个可重用的调度命令脚本,排队并检查了一个一次性的 at 任务,配置了一个周期性的 cron 插入式文件,在 /usr/local/bin 下安装了一个服务安全命令,创建了一个 systemd 服务与定时器对,手动测试了定时器服务,并移除了临时的 at 任务。