我正在将我的 cron 任务转换为 systemd 定时器。我已经使用定时器几年了,但通常,我只是学到足够完成我正在处理的任务的知识。在为这个 systemd 系列 进行研究时,我了解到 systemd 定时器有一些非常有趣的功能。
与 cron 任务一样,systemd 定时器可以在指定的时间间隔触发事件——shell 脚本和程序——例如每天一次,在每月的特定日期(可能仅在星期一),或在工作日的上午 8 点到下午 6 点之间每 15 分钟一次。定时器还可以执行 cron 任务无法完成的一些操作。例如,定时器可以触发脚本或程序在事件发生后特定时间运行,例如启动、启动、完成上一个任务,甚至是在定时器调用的服务单元上次完成之后。
系统维护定时器
当 Fedora 或任何基于 systemd 的发行版安装在新系统上时,它会创建多个定时器,这些定时器是任何 Linux 主机后台发生的系统维护过程的一部分。这些定时器触发常见维护任务所需的事件,例如更新系统数据库、清理临时目录、轮换日志文件等等。
例如,我将通过使用 systemctl status *timer
命令列出我的主工作站上的一些定时器,以查看我主机上的所有定时器。星号符号的工作方式与文件通配符相同,因此此命令列出所有 systemd 定时器单元
[root@testvm1 ~]# systemctl status *timer
● mlocate-updatedb.timer - Updates mlocate database every day
Loaded: loaded (/usr/lib/systemd/system/mlocate-updatedb.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 00:00:00 EDT; 15h left
Triggers: ● mlocate-updatedb.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Updates mlocate database every day.
● logrotate.timer - Daily rotation of log files
Loaded: loaded (/usr/lib/systemd/system/logrotate.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 00:00:00 EDT; 15h left
Triggers: ● logrotate.service
Docs: man:logrotate(8)
man:logrotate.conf(5)
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Daily rotation of log files.
● sysstat-summary.timer - Generate summary of yesterday's process accounting
Loaded: loaded (/usr/lib/systemd/system/sysstat-summary.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 00:07:00 EDT; 15h left
Triggers: ● sysstat-summary.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Generate summary of yesterday's process accounting.
● fstrim.timer - Discard unused blocks once a week
Loaded: loaded (/usr/lib/systemd/system/fstrim.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Mon 2020-06-08 00:00:00 EDT; 3 days left
Triggers: ● fstrim.service
Docs: man:fstrim
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Discard unused blocks once a week.
● sysstat-collect.timer - Run system activity accounting tool every 10 minutes
Loaded: loaded (/usr/lib/systemd/system/sysstat-collect.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Thu 2020-06-04 08:50:00 EDT; 41s left
Triggers: ● sysstat-collect.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Run system activity accounting tool every 10 minutes.
● dnf-makecache.timer - dnf makecache --timer
Loaded: loaded (/usr/lib/systemd/system/dnf-makecache.timer; enabled; vendor preset: enabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Thu 2020-06-04 08:51:00 EDT; 1min 41s left
Triggers: ● dnf-makecache.service
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started dnf makecache –timer.
● systemd-tmpfiles-clean.timer - Daily Cleanup of Temporary Directories
Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.timer; static; vendor preset: disabled)
Active: active (waiting) since Tue 2020-06-02 08:02:33 EDT; 2 days ago
Trigger: Fri 2020-06-05 08:19:00 EDT; 23h left
Triggers: ● systemd-tmpfiles-clean.service
Docs: man:tmpfiles.d(5)
man:systemd-tmpfiles(8)
Jun 02 08:02:33 testvm1.both.org systemd[1]: Started Daily Cleanup of Temporary Directories.
每个定时器都至少有六行与之相关联的信息
- 第一行包含定时器的文件名及其用途的简短描述。
- 第二行显示定时器的状态,是否已加载、定时器单元文件的完整路径以及供应商预设。
- 第三行指示其活动状态,其中包括定时器变为活动状态的日期和时间。
- 第四行包含定时器下次触发的日期和时间,以及直到触发发生的大概时间。
- 第五行显示由定时器触发的事件或服务的名称。
- 一些(但不是全部)systemd 单元文件具有指向相关文档的指针。我的虚拟机输出中的三个定时器具有指向文档的指针。这是一个很好的(但可选的)数据位。
- 最后一行是定时器触发的服务最近一次实例的日志条目。
根据您的主机,您可能会有一组不同的定时器。
创建定时器
虽然我们可以解构一个或多个现有定时器来了解它们的工作原理,但让我们创建我们自己的 服务单元 和一个定时器单元来触发它。我们将使用一个相当简单的示例,以使其保持简单。在我们完成此操作后,将更容易理解其他定时器的工作原理并确定它们正在做什么。
首先,创建一个简单的服务,它将运行一些基本的东西,例如 free
命令。例如,您可能想要定期监视可用内存。在 /etc/systemd/system
目录中创建以下 myMonitor.service
单元文件。它不需要是可执行文件
# This service unit is for testing timer units
# By David Both
# Licensed under GPL V2
#
[Unit]
Description=Logs system statistics to the systemd journal
Wants=myMonitor.timer
[Service]
Type=oneshot
ExecStart=/usr/bin/free
[Install]
WantedBy=multi-user.target
现在让我们查看状态并测试我们的服务单元,以确保它按我们的预期工作。
[root@testvm1 system]# systemctl status myMonitor.service
● myMonitor.service - Logs system statistics to the systemd journal
Loaded: loaded (/etc/systemd/system/myMonitor.service; disabled; vendor preset: disabled)
Active: inactive (dead)
[root@testvm1 system]# systemctl start myMonitor.service
[root@testvm1 system]#
输出在哪里?默认情况下,systemd 服务单元运行的程序的标准输出(STDOUT
)被发送到 systemd 日志,这会留下您可以现在或稍后查看的记录——直到某个时间点。(我将在本系列的未来文章中介绍 systemd 日志记录和保留策略。)专门查看您的服务单元的日志,并且仅针对今天。-S
选项是 --since
的简写版本,允许您指定 journalctl
工具应搜索条目的时间段。这并不是因为您不关心以前的结果——在这种情况下,不会有任何结果——而是为了缩短搜索时间,如果您的主机已经运行了很长时间并且在日志中累积了大量条目
[root@testvm1 system]# journalctl -S today -u myMonitor.service
-- Logs begin at Mon 2020-06-08 07:47:20 EDT, end at Thu 2020-06-11 09:40:47 EDT. --
Jun 11 09:12:09 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 11 09:12:09 testvm1.both.org free[377966]: total used free shared buff/cache available
Jun 11 09:12:09 testvm1.both.org free[377966]: Mem: 12635740 522868 11032860 8016 1080012 11821508
Jun 11 09:12:09 testvm1.both.org free[377966]: Swap: 8388604 0 8388604
Jun 11 09:12:09 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
[root@testvm1 system]#
由服务触发的任务可以是单个程序、一系列程序或以任何脚本语言编写的脚本。通过将以下行添加到 myMonitor.service
单元文件的 [Service]
部分的末尾,向服务添加另一个任务
ExecStart=/usr/bin/lsblk
再次启动服务并检查日志以查看结果,结果应如下所示。您应该在日志中看到来自两个命令的结果
Jun 11 15:42:18 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 11 15:42:18 testvm1.both.org free[379961]: total used free shared buff/cache available
Jun 11 15:42:18 testvm1.both.org free[379961]: Mem: 12635740 531788 11019540 8024 1084412 11812272
Jun 11 15:42:18 testvm1.both.org free[379961]: Swap: 8388604 0 8388604
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: sda 8:0 0 120G 0 disk
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ├─sda1 8:1 0 4G 0 part /boot
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: └─sda2 8:2 0 116G 0 part
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ├─VG01-root 253:0 0 5G 0 lvm /
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ├─VG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ├─VG01-usr 253:2 0 30G 0 lvm /usr
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ├─VG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: ├─VG01-var 253:4 0 20G 0 lvm /var
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: └─VG01-home 253:5 0 10G 0 lvm /home
Jun 11 15:42:18 testvm1.both.org lsblk[379962]: sr0 11:0 1 1024M 0 rom
Jun 11 15:42:18 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 11 15:42:18 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
现在您知道您的服务按预期工作,在 /etc/systemd/system
中创建定时器单元文件 myMonitor.timer
,并添加以下内容
# This timer unit is for testing
# By David Both
# Licensed under GPL V2
#
[Unit]
Description=Logs some system statistics to the systemd journal
Requires=myMonitor.service
[Timer]
Unit=myMonitor.service
OnCalendar=*-*-* *:*:00
[Install]
WantedBy=timers.target
myMonitor.timer 文件
中的 OnCalendar
时间规范 *-*-* *:*:00
应该触发定时器每分钟执行一次 myMonitor.service
单元。我将在本文稍后探讨 OnCalendar
设置。
现在,观察与定时器触发时运行您的服务相关的任何日志条目。您也可以跟踪定时器,但跟踪服务可以让您近乎实时地看到结果。使用 -f
(跟踪)选项运行 journalctl
[root@testvm1 system]# journalctl -S today -f -u myMonitor.service
-- Logs begin at Mon 2020-06-08 07:47:20 EDT. --
启动但不启用定时器,看看它运行一段时间后会发生什么
[root@testvm1 ~]# systemctl start myMonitor.service
[root@testvm1 ~]#
一个结果立即显示出来,下一个结果以——大概——一分钟的间隔出现。观察日志几分钟,看看您是否注意到我注意到的相同内容
[root@testvm1 system]# journalctl -S today -f -u myMonitor.service
-- Logs begin at Mon 2020-06-08 07:47:20 EDT. --
Jun 13 08:39:18 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 13 08:39:18 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 13 08:39:19 testvm1.both.org free[630566]: total used free shared buff/cache available
Jun 13 08:39:19 testvm1.both.org free[630566]: Mem: 12635740 556604 10965516 8036 1113620 11785628
Jun 13 08:39:19 testvm1.both.org free[630566]: Swap: 8388604 0 8388604
Jun 13 08:39:18 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: sda 8:0 0 120G 0 disk
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ├─sda1 8:1 0 4G 0 part /boot
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: └─sda2 8:2 0 116G 0 part
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ├─VG01-root 253:0 0 5G 0 lvm /
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ├─VG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ├─VG01-usr 253:2 0 30G 0 lvm /usr
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ├─VG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: ├─VG01-var 253:4 0 20G 0 lvm /var
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: └─VG01-home 253:5 0 10G 0 lvm /home
Jun 13 08:39:19 testvm1.both.org lsblk[630567]: sr0 11:0 1 1024M 0 rom
Jun 13 08:40:46 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 13 08:40:46 testvm1.both.org free[630572]: total used free shared buff/cache available
Jun 13 08:40:46 testvm1.both.org free[630572]: Mem: 12635740 555228 10966836 8036 1113676 11786996
Jun 13 08:40:46 testvm1.both.org free[630572]: Swap: 8388604 0 8388604
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: sda 8:0 0 120G 0 disk
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ├─sda1 8:1 0 4G 0 part /boot
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: └─sda2 8:2 0 116G 0 part
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ├─VG01-root 253:0 0 5G 0 lvm /
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ├─VG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ├─VG01-usr 253:2 0 30G 0 lvm /usr
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ├─VG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: ├─VG01-var 253:4 0 20G 0 lvm /var
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: └─VG01-home 253:5 0 10G 0 lvm /home
Jun 13 08:40:46 testvm1.both.org lsblk[630574]: sr0 11:0 1 1024M 0 rom
Jun 13 08:40:46 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 13 08:40:46 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
Jun 13 08:41:46 testvm1.both.org systemd[1]: Starting Logs system statistics to the systemd journal...
Jun 13 08:41:46 testvm1.both.org free[630580]: total used free shared buff/cache available
Jun 13 08:41:46 testvm1.both.org free[630580]: Mem: 12635740 553488 10968564 8036 1113688 11788744
Jun 13 08:41:46 testvm1.both.org free[630580]: Swap: 8388604 0 8388604
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: sda 8:0 0 120G 0 disk
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ├─sda1 8:1 0 4G 0 part /boot
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: └─sda2 8:2 0 116G 0 part
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ├─VG01-root 253:0 0 5G 0 lvm /
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ├─VG01-swap 253:1 0 8G 0 lvm [SWAP]
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ├─VG01-usr 253:2 0 30G 0 lvm /usr
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ├─VG01-tmp 253:3 0 10G 0 lvm /tmp
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: ├─VG01-var 253:4 0 20G 0 lvm /var
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: └─VG01-home 253:5 0 10G 0 lvm /home
Jun 13 08:41:47 testvm1.both.org lsblk[630581]: sr0 11:0 1 1024M 0 rom
Jun 13 08:41:47 testvm1.both.org systemd[1]: myMonitor.service: Succeeded.
Jun 13 08:41:47 testvm1.both.org systemd[1]: Finished Logs system statistics to the systemd journal.
务必检查定时器和服务两者的状态。
您可能在日志中至少注意到了两件事。首先,您不需要做任何特殊的事情来使 myMonitor.service
单元中 ExecStart
触发器的 STDOUT
存储在日志中。这都是使用 systemd 运行服务的一部分。但是,这确实意味着您可能需要注意从服务单元运行脚本以及它们生成多少 STDOUT
。
第二件事是定时器不会在 :00 秒整分或甚至正好在上次实例后一分钟触发。这是故意的,但如果需要(或者如果它只是冒犯了您的系统管理员的敏感性),则可以覆盖它。
此行为的原因是为了防止多个服务在完全相同的时间触发。例如,您可以使用诸如 Weekly、Daily 等时间规范。这些快捷方式都定义为在触发日期的 00:00:00 小时触发。当以这种方式指定多个定时器时,它们很可能会尝试同时启动。
systemd 定时器被有意设计为在指定时间附近以某种随机方式触发,以尝试防止同时触发。它们在指定触发时间开始并在指定时间加上一分钟结束的时间窗口内半随机地触发。根据 systemd.timer
手册页,此触发时间相对于所有其他定义的定时器单元保持在稳定的位置。您可以在上面的日志条目中看到,定时器在启动时立即触发,然后在每分钟后大约 46 或 47 秒触发。
大多数情况下,这种概率触发时间是没问题的。当安排备份等任务运行时,只要它们在非工作时间运行,就不会有问题。系统管理员可以选择确定性的开始时间,例如典型 cron 任务规范中的 01:05:00,以避免与其他任务冲突,但是有很大范围的时间值可以完成该任务。启动时间中一分钟的随机性通常是无关紧要的。
但是,对于某些任务,精确的触发时间是绝对的要求。对于这些任务,您可以通过在定时器单元文件的 Timer
部分中添加如下语句来指定更高的触发时间跨度精度(在微秒内)
AccuracySec=1us
时间跨度可用于指定所需的精度,以及定义重复或一次性事件的时间跨度。它识别以下单位
- 微秒, us, µs
- 毫秒, ms
- 秒, 秒, 秒, s
- 分钟, 分钟, 分, m
- 小时, 小时, 小时, h
- 天, 天, d
- 周, 周, w
- 月, 月, M(定义为 30.44 天)
- 年, 年, y(定义为 365.25 天)
/usr/lib/systemd/system
中的所有默认定时器都指定了更大的精度范围,因为精确时间并不重要。查看系统创建的定时器中的一些规范
[root@testvm1 system]# grep Accur /usr/lib/systemd/system/*timer
/usr/lib/systemd/system/fstrim.timer:AccuracySec=1h
/usr/lib/systemd/system/logrotate.timer:AccuracySec=1h
/usr/lib/systemd/system/logwatch.timer:AccuracySec=12h
/usr/lib/systemd/system/mlocate-updatedb.timer:AccuracySec=24h
/usr/lib/systemd/system/raid-check.timer:AccuracySec=24h
/usr/lib/systemd/system/unbound-anchor.timer:AccuracySec=24h
[root@testvm1 system]#
查看 /usr/lib/systemd/system
目录中某些定时器单元文件的完整内容,以了解它们的构造方式。
您不必在此实验中启用定时器以在启动时激活它,但执行此操作的命令是
# systemctl enable myMonitor.timer
您创建的单元文件不需要是可执行文件。您也没有启用服务单元,因为它是由定时器触发的。如果您愿意,您仍然可以从命令行手动触发服务单元。尝试这样做并观察日志。
有关定时器精度、事件时间规范和触发事件的更多信息,请参阅 systemd.timer
和 systemd.time
的手册页。
定时器类型
systemd 定时器具有 cron 中没有的其他功能,cron 仅在特定的、重复的、实时日期和时间触发。可以将 systemd 定时器配置为基于其他 systemd 单元中的状态更改来触发。例如,可以将定时器配置为在系统启动、启动或定义的服务单元激活后的特定经过时间后触发。这些称为单调定时器。单调是指不断增加的计数或序列。这些定时器不是持久性的,因为它们在每次启动后都会重置。
表 1 列出了单调定时器及其每个的简短定义,以及 OnCalendar
定时器,它不是单调的,用于指定可能是或可能不是重复的未来时间。此信息来自 systemd.timer
手册页,并进行了一些小的更改。
定时器 | 单调 | 定义 |
---|---|---|
OnActiveSec= |
X | 这定义了相对于定时器激活时刻的定时器。 |
OnBootSec= |
X | 这定义了相对于机器启动时间的定时器。 |
OnStartupSec= |
X | 这定义了相对于服务管理器首次启动时间的定时器。对于系统定时器单元,这与 OnBootSec= 非常相似,因为系统服务管理器通常在启动时很早就启动。当在每个用户服务管理器中运行的单元中配置时,它主要有用,因为用户服务管理器通常仅在首次登录时启动,而不是在启动期间启动。 |
OnUnitActiveSec= |
X | 这定义了相对于要激活的定时器上次激活时间的定时器。 |
OnUnitInactiveSec= |
X | 这定义了相对于要激活的定时器上次停用时间的定时器。 |
OnCalendar= |
这定义了具有日历事件表达式的实时(即挂钟)定时器。有关日历事件表达式语法的更多信息,请参阅 systemd.time(7) 。否则,语义类似于 OnActiveSec= 和相关设置。此定时器是最像 cron 服务中使用的定时器。 |
表 1:systemd 定时器定义
单调定时器可以使用与之前提到的 AccuracySec
语句相同的时间跨度快捷名称,但 systemd 会将这些名称标准化为秒。例如,您可能想要指定一个定时器,该定时器在系统启动后五天触发一次事件;它可能看起来像这样:OnBootSec=5d
。如果主机在 2020-06-15 09:45:27
启动,则定时器将在 2020-06-20 09:45:27
或之后一分钟内触发。
日历事件规范
日历事件规范是在所需的重复时间触发定时器的关键部分。首先查看 OnCalendar
设置中使用的一些规范。
systemd 及其定时器使用的时间和日期规范样式与 crontab 中使用的格式不同。它比 crontab 更灵活,并且允许像 at
命令那样使用模糊的日期和时间。它也应该足够熟悉,以便易于理解。
使用 OnCalendar=
的 systemd 定时器的基本格式是 DOW YYYY-MM-DD HH:MM:SS
。DOW(星期几)是可选的,其他字段可以使用星号 (*) 来匹配该位置的任何值。所有日历时间形式都转换为规范化形式。如果未指定时间,则假定为 00:00:00。如果未指定日期但指定了时间,则下一个匹配项可能是今天或明天,具体取决于当前时间。名称或数字可用于月份和星期几。可以指定每个单元的逗号分隔列表。可以使用 ..
在开始值和结束值之间指定单元范围。
指定日期有几个有趣的选项。波浪号 (~) 可用于指定月份的最后一天或月份最后一天之前的指定天数。“/” 可用于将星期几指定为修饰符。
以下是一些 OnCalendar
语句中使用的典型时间规范的示例。
日历事件规范 | 描述 |
---|---|
DOW YYYY-MM-DD HH:MM:SS | |
*-*-* 00:15:30 | 每年每月每天午夜 15 分 30 秒 |
每周 | 每周一 00:00:00 |
Mon *-*-* 00:00:00 | 与每周相同 |
Mon | 与每周相同 |
Wed 2020-*-* | 2020 年每个星期三 00:00:00 |
Mon..Fri 2021-*-* | 2021 年每个工作日 00:00:00 |
2022-6,7,8-1,15 01:15:00 | 2022 年 6 月、7 月和 8 月的 1 号和 15 号凌晨 01:15:00 |
Mon *-05~03 | 任何年份 5 月的下一个星期一,也是该月倒数第 3 天。 |
Mon..Fri *-08~04 | 任何年份 8 月倒数第 4 天,并且也恰逢工作日。 |
*-05~03/2 | 5 月份倒数第三天,然后两天后再次出现。每年重复。请注意,此表达式使用波浪号 (~)。 |
*-05-03/2 | 5 月份的第三天,然后在 5 月剩余的每一天每隔一天。每年重复。请注意,此表达式使用短划线 (-)。 |
表 2:OnCalendar
事件规范示例
测试日历规范
systemd 提供了一个出色的工具,用于验证和检查定时器中的日历时间事件规范。systemd-analyze calendar
工具解析日历时间事件规范,并提供规范化形式以及其他有趣的信息,例如下一个“经过”的日期和时间,即匹配,以及到达触发时间之前的大概时间。
首先,查看未来没有时间的日期(请注意,Next elapse
和 UTC
的时间将根据您当地的时区而有所不同)
[student@studentvm1 ~]$ systemd-analyze calendar 2030-06-17
Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00
Next elapse: Mon 2030-06-17 00:00:00 EDT
(in UTC): Mon 2030-06-17 04:00:00 UTC
From now: 10 years 0 months left
[root@testvm1 system]#
现在添加时间。在本示例中,日期和时间被分别分析为不相关的实体
[root@testvm1 system]# systemd-analyze calendar 2030-06-17 15:21:16
Original form: 2030-06-17
Normalized form: 2030-06-17 00:00:00
Next elapse: Mon 2030-06-17 00:00:00 EDT
(in UTC): Mon 2030-06-17 04:00:00 UTC
From now: 10 years 0 months left
Original form: 15:21:16
Normalized form: *-*-* 15:21:16
Next elapse: Mon 2020-06-15 15:21:16 EDT
(in UTC): Mon 2020-06-15 19:21:16 UTC
From now: 3h 55min left
[root@testvm1 system]#
要将日期和时间作为一个单元进行分析,请将它们一起括在引号中。请务必在使用定时器单元中的 OnCalendar=
事件规范时删除引号,否则您将收到错误
[root@testvm1 system]# systemd-analyze calendar "2030-06-17 15:21:16"
Normalized form: 2030-06-17 15:21:16
Next elapse: Mon 2030-06-17 15:21:16 EDT
(in UTC): Mon 2030-06-17 19:21:16 UTC
From now: 10 years 0 months left
[root@testvm1 system]#
现在测试表 2 中的条目。我特别喜欢最后一个
[root@testvm1 system]# systemd-analyze calendar "2022-6,7,8-1,15 01:15:00"
Original form: 2022-6,7,8-1,15 01:15:00
Normalized form: 2022-06,07,08-01,15 01:15:00
Next elapse: Wed 2022-06-01 01:15:00 EDT
(in UTC): Wed 2022-06-01 05:15:00 UTC
From now: 1 years 11 months left
[root@testvm1 system]#
让我们看一个示例,其中我们列出了时间戳表达式的下五个经过时间。
[root@testvm1 ~]# systemd-analyze calendar --iterations=5 "Mon *-05~3"
Original form: Mon *-05~3
Normalized form: Mon *-05~03 00:00:00
Next elapse: Mon 2023-05-29 00:00:00 EDT
(in UTC): Mon 2023-05-29 04:00:00 UTC
From now: 2 years 11 months left
Iter. #2: Mon 2028-05-29 00:00:00 EDT
(in UTC): Mon 2028-05-29 04:00:00 UTC
From now: 7 years 11 months left
Iter. #3: Mon 2034-05-29 00:00:00 EDT
(in UTC): Mon 2034-05-29 04:00:00 UTC
From now: 13 years 11 months left
Iter. #4: Mon 2045-05-29 00:00:00 EDT
(in UTC): Mon 2045-05-29 04:00:00 UTC
From now: 24 years 11 months left
Iter. #5: Mon 2051-05-29 00:00:00 EDT
(in UTC): Mon 2051-05-29 04:00:00 UTC
From now: 30 years 11 months left
[root@testvm1 ~]#
这应该为您提供足够的信息来开始测试您的 OnCalendar
时间规范。systemd-analyze
工具可用于其他有趣的分析,我将在本系列的下一篇文章中开始探讨。
摘要
systemd 定时器可用于执行与 cron 工具相同类型的任务,但在触发事件的日历和单调时间规范方面提供了更大的灵活性。
即使您为此实验创建的服务单元通常由定时器触发,您也可以使用 systemctl start myMonitor.service
命令随时触发它。可以在单个定时器中编写多个维护任务脚本;这些可以是 Bash 脚本或 Linux 实用程序程序。您可以运行由定时器触发的服务来运行所有脚本,也可以根据需要运行单个脚本。
我将在下一篇文章中更详细地探讨 systemd 对时间和时间规范的使用。
我尚未看到任何迹象表明 cron
和 at
将被弃用。我希望这不会发生,因为至少 at
比 systemd 定时器更容易用于一次性任务调度。
资源
互联网上有大量关于 systemd 的信息,但其中许多信息都很简洁、晦涩甚至具有误导性。除了本文中提到的资源外,以下网页还提供了关于 systemd 启动的更详细和可靠的信息。
- Fedora 项目有一个很好的、实用的 systemd 指南。它几乎包含了您需要了解的所有内容,以便使用 systemd 配置、管理和维护 Fedora 计算机。
- Fedora 项目还有一个很好的 速查表,它将旧的 SystemV 命令交叉引用到可比较的 systemd 命令。
- 有关 systemd 的详细技术信息以及创建 systemd 的原因,请查看 Freedesktop.org 的 systemd 描述。
- Linux.com 的“更多 systemd 乐趣”提供了更高级的 systemd 信息和技巧。
Lennart Poettering(systemd 的设计者和主要开发者)还为 Linux 系统管理员撰写了一系列深入的技术文章。这些文章写于 2010 年 4 月至 2011 年 9 月之间,但它们现在仍然像当时一样相关。关于 systemd 及其生态系统所写的一切优秀文章,大部分都基于这些论文。
10 条评论