Systemd 定時器教程
Systemd 作為 Linux 的系統啟動器,功能強大。
本文通過一個簡單例子,介紹 Systemd 如何設置定時任務。這不僅實用,而且可以作為 Systemd 的上手教程。
一、定時任務
所謂定時任務,就是未來的某個或多個時點,預定要執行的任務,比如每五分鍾收一次郵件、每天半夜兩點分析一下日志等等。
Linux 系統通常都使用 cron 設置定時任務,但是 Systemd 也有這個功能,而且優點顯著。
- 自動生成日志,配合 Systemd 的日志工具,很方便除錯
- 可以設置內存和 CPU 的使用額度,比如最多使用50%的 CPU
- 任務可以拆分,依賴其他 Systemd 單元,完成非常復雜的任務
下面,我就來演示一個 Systemd 定時任務:每小時發送一封電子郵件。
二、郵件腳本
先寫一個發郵件的腳本mail.sh
。
#!/usr/bin/env bash echo "This is the body" | /usr/bin/mail -s "Subject" someone@example.com
上面代碼的someone@example.com
,請替換成你的郵箱地址。
然后,執行這個腳本。
$ bash mail.sh
執行后,你應該就會收到一封郵件,標題為Subject
。
如果你的 Linux 系統不能發郵件,建議安裝 ssmtp 或者 msmtp。另外,mail
命令的用法,可以參考這里。
三、Systemd 單元
學習 Systemd 的第一步,就是搞懂"單元"(unit)是什么。
簡單說,單元就是 Systemd 的最小功能單位,是單個進程的描述。一個個小的單元互相調用和依賴,組成一個龐大的任務管理系統,這就是 Systemd 的基本思想。
由於 Systemd 要做的事情太多,導致單元有很多不同的種類,大概一共有12種。舉例來說,Service 單元負責后台服務,Timer 單元負責定時器,Slice 單元負責資源的分配。
每個單元都有一個單元描述文件,它們分散在三個目錄。
/lib/systemd/system
:系統默認的單元文件/etc/systemd/system
:用戶安裝的軟件的單元文件/usr/lib/systemd/system
:用戶自己定義的單元文件
下面的命令可以查看所有的單元文件。
# 查看所有單元 $ systemctl list-unit-files # 查看所有 Service 單元 $ systemctl list-unit-files --type service # 查看所有 Timer 單元 $ systemctl list-unit-files --type timer
四、單元的管理命令
下面是常用的單元管理命令。
# 啟動單元 $ systemctl start [UnitName] # 關閉單元 $ systemctl stop [UnitName] # 重啟單元 $ systemctl restart [UnitName] # 殺死單元進程 $ systemctl kill [UnitName] # 查看單元狀態 $ systemctl status [UnitName] # 開機自動執行該單元 $ systemctl enable [UnitName] # 關閉開機自動執行 $ systemctl disable [UnitName]
五、Service 單元
前面說過,Service 單元就是所要執行的任務,比如發送郵件就是一種 Service。
新建 Service 非常簡單,就是在/usr/lib/systemd/system
目錄里面新建一個文件,比如mytimer.service
文件,你可以寫入下面的內容。
[Unit] Description=MyTimer [Service] ExecStart=/bin/bash /path/to/mail.sh
可以看到,這個 Service 單元文件分成兩個部分。
[Unit]
部分介紹本單元的基本信息(即元數據),Description
字段給出這個單元的簡單介紹(名字叫做MyTimer
)。
[Service]
部分用來定制行為,Systemd 提供許多字段。
ExecStart
:systemctl start
所要執行的命令ExecStop
:systemctl stop
所要執行的命令ExecReload
:systemctl reload
所要執行的命令ExecStartPre
:ExecStart
之前自動執行的命令ExecStartPost
:ExecStart
之后自動執行的命令ExecStopPost
:ExecStop
之后自動執行的命令
注意,定義的時候,所有路徑都要寫成絕對路徑,比如bash
要寫成/bin/bash
,否則 Systemd 會找不到。
現在,啟動這個 Service。
$ sudo systemctl start mytimer.service
如果一切正常,你應該就會收到一封郵件。
六、Timer 單元
Service 單元只是定義了如何執行任務,要定時執行這個 Service,還必須定義 Timer 單元。
/usr/lib/systemd/system
目錄里面,新建一個mytimer.timer
文件,寫入下面的內容。
[Unit] Description=Runs mytimer every hour [Timer] OnUnitActiveSec=1h Unit=mytimer.service [Install] WantedBy=multi-user.target
這個 Timer 單元文件分成幾個部分。
[Unit]
部分定義元數據。
[Timer]
部分定制定時器。Systemd 提供以下一些字段。
OnActiveSec
:定時器生效后,多少時間開始執行任務OnBootSec
:系統啟動后,多少時間開始執行任務OnStartupSec
:Systemd 進程啟動后,多少時間開始執行任務OnUnitActiveSec
:該單元上次執行后,等多少時間再次執行OnUnitInactiveSec
: 定時器上次關閉后多少時間,再次執行OnCalendar
:基於絕對時間,而不是相對時間執行AccuracySec
:如果因為各種原因,任務必須推遲執行,推遲的最大秒數,默認是60秒Unit
:真正要執行的任務,默認是同名的帶有.service
后綴的單元Persistent
:如果設置了該字段,即使定時器到時沒有啟動,也會自動執行相應的單元WakeSystem
:如果系統休眠,是否自動喚醒系統
上面的腳本里面,OnUnitActiveSec=1h
表示一小時執行一次任務。其他的寫法還有OnUnitActiveSec=*-*-* 02:00:00
表示每天凌晨兩點執行,OnUnitActiveSec=Mon *-*-* 02:00:00
表示每周一凌晨兩點執行,具體請參考官方文檔。
七、[Install] 和 target
mytimer.timer
文件里面,還有一個[Install]
部分,定義開機自啟動(systemctl enable
)和關閉開機自啟動(systemctl disable
)這個單元時,所要執行的命令。
上面腳本中,[Install]
部分只寫了一個字段,即WantedBy=multi-user.target
。它的意思是,如果執行了systemctl enable mytimer.timer
(只要開機,定時器自動生效),那么該定時器歸屬於multi-user.target
。
所謂 Target 指的是一組相關進程,有點像 init 進程模式下面的啟動級別。啟動某個Target 的時候,屬於這個 Target 的所有進程都會全部啟動。
multi-user.target
是一個最常用的 Target,意為多用戶模式。也就是說,當系統以多用戶模式啟動時,就會一起啟動mytimer.timer
。它背后的操作其實很簡單,執行systemctl enable mytimer.timer
命令時,就會在multi-user.target.wants
目錄里面創建一個符號鏈接,指向mytimer.timer
。
八、定時器的相關命令
下面,啟動剛剛新建的這個定時器。
$ sudo systemctl start mytimer.timer
你應該立刻就會收到郵件,然后每個小時都會收到同樣郵件。
查看這個定時器的狀態。
$ systemctl status mytimer.timer
查看所有正在運行的定時器。
$ systemctl list-timers
關閉這個定時器。
$ sudo systemctl stop myscript.timer
下次開機,自動運行這個定時器。
$ sudo systemctl enable myscript.timer
關閉定時器的開機自啟動。
$ sudo systemctl disable myscript.timer
九、日志相關命令
如果發生問題,就需要查看日志。Systemd 的日志功能很強,提供統一的命令。
# 查看整個日志 $ sudo journalctl # 查看 mytimer.timer 的日志 $ sudo journalctl -u mytimer.timer # 查看 mytimer.timer 和 mytimer.service 的日志 $ sudo journalctl -u mytimer # 從結尾開始查看最新日志 $ sudo journalctl -f # 從結尾開始查看 mytimer.timer 的日志 $ journalctl -f -u timer.timer
十、參考鏈接
- How to Use Systemd Timers, by Jason Graham
- Using systemd as a better cron, by luqmaan
- Getting started with systemd, by CoreOS
- systemd/Timers, by ArchWiki
- Understanding Systemd Units and Unit Files, by Justin Ellingwood
(完)