Cron表示式轉systemd定時器工具
免費工具,將cron表示式(分 時 日 月 星期)轉換為systemd定時器的OnCalendar=語法。同時對日期與星期同時限定時的OR語義差異進行提示,適用於將cron任務遷移到Docker/Kubernetes環境。
cron欄位與systemd組成部分對照表
cron表示式的5個欄位與systemd的OnCalendar=語法對應關係如下。
| 位置 | cron欄位 | systemd對應部分 |
|---|---|---|
| 1 | 分鐘 | 時間部分的分鐘(HH:MM:SS中的MM) |
| 2 | 小時 | 時間部分的小時(HH:MM:SS中的HH) |
| 3 | 日(日期) | 日期部分的日(年-月-日中的日) |
| 4 | 月 | 日期部分的月(年-月-日中的月) |
| 5 | 星期 | 星期字首(例如Mon、Mon..Fri) |
由於cron沒有秒欄位,systemd的秒部分始終為"00"。當日期和月份均不受限(*)時,systemd的年-月-日部分可以完全省略。
cron星期編號與systemd星期縮寫對照表
cron用0〜7的數字表示星期,而systemd使用英文星期縮寫。
| cron星期編號 | systemd星期縮寫 |
|---|---|
| 0 (7) | Sun |
| 1 | Mon |
| 2 | Tue |
| 3 | Wed |
| 4 | Thu |
| 5 | Fri |
| 6 | Sat |
常見轉換示例
| cron表示式 | OnCalendar= | 含義 |
|---|---|---|
| * * * * * |
OnCalendar=*-*-* *:*:00
|
每分鐘執行一次(相當於cron的"* * * * *")。 |
| */15 * * * * |
OnCalendar=*:00/15:00
|
每15分鐘執行一次。 |
| 0 9 * * 1-5 |
OnCalendar=Mon..Fri 09:00:00
|
工作日(週一至週五)上午9點執行。 |
| 0 0 1 * * |
OnCalendar=*-*-01 00:00:00
|
每月1日0點執行。 |
| 0 0 1 1 * |
OnCalendar=*-01-01 00:00:00
|
每年1月1日0點執行。 |
| 0 0 1 * 1 |
OnCalendar=Mon 00:00:00
OnCalendar=*-*-01 00:00:00
|
同時指定日期(1日)與星期(週一)的範例。在 cron 中這是 OR 條件(滿足其一即執行)。若寫成一行「Mon *-*-01」就會變成 AND 條件(1日且是週一),一年只執行一到三次,因此拆成兩行以保持相同的意思。 |
同時限定日期與星期(都不以 * 開頭)的 cron 表示式,如果寫成一行 OnCalendar=,意思就會改變(cron 是 OR,而 systemd 在一行內是 AND)。在同一個 .timer 單元中分成星期一行、日期一行來寫,就會在符合其中任一條件的日子執行,與 cron 的意思相同。
把 cron 式改寫成 systemd 計時器
要把排程由 cron 遷往 systemd 計時器,便須把「分 時 日 月 星期」這五個欄位譯成 OnCalendar= 的寫法。輸入一條 cron 式,本工具便產出與之對應的 OnCalendar=,並把值得當心之處一併報作警告。
這道轉換中最要緊的,是「日」與「星期」同時給出時二者的脾性。 cron 把這兩者讀作或:0 0 1 * 1 意為「每月一日或每個星期一」,一個月裡可能跑上五回。而 systemd 的 OnCalendar= 卻把同樣的寫法當作與。 它成了「一日且星期一」,一年裡只跑一到三回。機械地照搬,作業的跑動頻次便悄然變了。 本工具會偵出這一組合,並把 OnCalendar= 拆成兩行,保住原來的意思。
轉換的步驟
- 輸入 cron 式 把分、時、日、月、星期這五個欄位以空格分開寫出。
- 查看產生的 OnCalendar= 您會得到與之對應的 systemd 寫法。
- 閱讀警告 日與星期同時給出時,含義的變動會被點出來。
-
謄進計時器單元
貼進
.timer檔案的[Timer]一節即可。
用好本工具的小技巧
- 如果同時限定日期與星期,cron 會按 OR 條件解釋。由於 systemd 在一行內按 AND 處理,本工具會輸出兩行 OnCalendar=(一個定時器寫多行時,只要符合其中任意一行就會執行)。
- Debian、Ubuntu 系的官方 Docker 映像等最小化容器往往不含 cron 守護程序(Alpine Linux 內建 BusyBox 的 crond,但需要自行啟動)。如果主機執行 systemd,遷移到 systemd 定時器是一個實用的選擇。
- 可以使用"systemd-analyze calendar"命令驗證生成的OnCalendar行,該命令還會顯示接下來的計劃執行時間。
- 與單行crontab不同,systemd定時器由兩個檔案組成:.timer單元(計劃部分)和.service單元(實際執行的任務)。
- systemd 的重複寫法(例如 00/15)無法指定結束值,因此 cron 中「10-20/5」這類範圍內的步長會展開為「10,15,20」這樣的列舉。星期的步長(*/2)在 systemd 中也不能寫成「Sun/2」,所以會展開為「Sun,Tue,Thu,Sat」。
這些情境會用到
遷往容器環境
容器裡往往沒有 cron 守護行程,排程便須遷往 systemd 計時器或別的安排。
想留下執行的紀錄
systemd 計時器會在 journald 裡留痕,事後可以追查。
想讓作業之間有相依
「在另一單元啟動之後再跑」這類事,cron 表達不出來。
盤點既有的排程
把一批 cron 式一併轉換,正是核對間隔是否合乎本意的好時機。
排程的術語
- cron 式
- 以分、時、日、月、星期五個欄位表示時刻的寫法。日與星期被讀作或。
- OnCalendar=
- 在 systemd 計時器中言明時刻的鍵。日與星期被讀作與。
- 計時器單元
- 副檔名為
.timer的檔案,它啟動同名的.service。 - Persistent=
- 該跑的時刻系統若正停著,此設定會讓計時器開機後補跑。 其行事與 cron 的
anacron相仿。 - AccuracySec=
- 觸發時刻的容差。預設有一分鐘的寬裕,故須嚴絲合縫時應予指明。
- journald
- systemd 的日誌收集機制。由計時器啟動的作業,其輸出亦存於此。
常見問題
閒話 ― 從cron到systemd定時器
systemd大約於2010年前後作為管理Linux啟動流程的初始化系統出現,此後成為大多數發行版的標準配置。其中的定時器功能與cron類似,提供週期性執行能力,但增加了cron從未擁有的功能:依賴關係解析、通過journalctl集中管理執行日誌,以及可配置的失敗重試行為。
與此同時,Docker和Kubernetes等容器環境中,為了保持映象體積小巧,越來越多的基礎映象根本不包含cron守護程序。當需要在此類環境中執行週期性任務時,現實的選擇要麼依賴Kubernetes CronJob等編排層面的機制,要麼在主機本身執行systemd的情況下交給systemd定時器處理。
OnCalendar=語法比cron的5個欄位表達能力更強,支援指定年份精度和秒級精度,但正因如此,一些cron表示式(同時限定日期與星期的OR條件)在簡單轉換下會改變含義。本工具明確地提示這一警告,正是為了讓遷移過程不至於陷入這個容易被忽略的陷阱。