Raspberry Piで定期的に実行したいジョブがあったので cronジョブとして実行しようかと思ってましたが、 systemdで定期実行する、ということをやってみたかったので systemdでやってみることにしました。
やりたいこと
cronジョブで書けば
0 12 * * * /path/to/script
みたいな感じで毎日お昼の12:00に実行するようなもの。
これを最近Linuxでは主に使われているサービス管理システムであるsystemdを使って作る、というもの。
実行用サービスの準備
これをやるために、まず以下の様なサービスを用意します。
1 2 3 4 5 6 7 8 9 |
|
Type
に関しては、このジョブはタイマーで起動し、一回限り、
終わったら終了、というものにしたいのでoneshot
に。
oneshot
はExecStart
のコマンドが終了したら起動完了、として通知します。
通常使うsimple
にするとExexStart
を実行した時点で起動完了として、
通常そのまま生き続ける様なものに使います。
WantedBy
でmulti-user.target
を指定して
通常の起動でGUIがない場合でも有効にする、
という指定で、これは他のサービスでもだいたい同じ様に設定するものです。
Timerサービスの準備
次に上のサービスを定期的に実行するタイマーを作ります。
1 2 3 4 5 6 7 8 9 |
|
こんな感じ。
まず、Install
のセクションでWantedBy
がtimers.target
を指定しています。
これによってタイマーとしてジョブを起動するようになります。
後はタイマーの定義をTimer
セクションで行います。
OnCalendar = *-*-* 12:00:00
で毎日12時に実行、になります。
cronジョブとは逆で普通な感じで年-月-日 時:分:秒
と書いてあります。
cronのように1,2,3
で1,2,3のとき、1..5
みたいな書き方で1~5、0/5
で5置き、という書き方も各項目で出来ます。
曜日もSun 20:00:00
みたいな感じで日曜の20時に、という指定も可能。
Mon,Wed
で複数にしたり、Mon..Fri
で月曜から金曜、というのも可能。
それら以外にweekly
、daily
、hourly
といった任意の時間に定期的に実行する、という指定も可能。
AccuracySec
は1s
で1秒、と設定していますが、
デフォルトでこの値は1m
で1分です。
この値の範囲内に始まる、ということなので、 デフォルトでは12:00:00に設定すると12:01:00までの間のどこかで始まる、ということになります。
ちょっと正確に時間を使いたかったので1秒にしてありますが、
最小で1us
(1マイクロ秒)まで小さく出来ます。
一方、これを小さくすればするほど時間を管理するためにCPU利用率が上がるので 最大限許容範囲で大きくした方が良いとのこと。 ジョブ自体が数秒かかるものだったりミリ秒以下の必要がなかったので1sにしてあります。
ただ、Raspberry Pi Zeroで1us
で動かしていても目に見えたCPU利用率の変化はありませんでした。
タイマー内で呼び出すサービスを指定していませんが この場合は同じディレクトリにある同じ名前のサービスを呼び出します。 今回はmyjob.service、myjob.timer、とサービスとタイマーが同じ名前のため myjob.serviceが呼び出される、ということに。
もし、別のサービスを呼び出したい場合には、
1 2 3 4 5 6 7 8 9 10 |
|
の様な感じでTimerセクションの中にUnit
という変数を入れて
そこにサービス名を指定します。
登録
myjob.service、myjob.timer の2つのファイルを /etc/systemd/system/に入れて
$ sudo systemctl daemon-reload
$ sudo systemctl enable myjob.timer
$ sudo systemctl start myjob.timer
で有効にしてスタート。
cronジョブとの違い
cronジョブと違って良い点は
- 秒単位で指定ができる
- 他のsystemdユニットへの依存関係が使える
- runレベルの指定ができる
- systemdでの管理で簡単に有効、無効化ができる
- journaldでログが管理できる
- cgroupsで管理できる
悪い点としては
- 1つのスクリプトを実行したいだけでも2つのファイルが必要で内容も多くなってしまう
- メールで通知したい場合、結構面倒
- メール通知用スクリプト、それを実行する
Type = oneshot
なサービスを別途用意してUnitセクションにOnFailure=<service>
のような形で設定する
- メール通知用スクリプト、それを実行する
という感じ。 なのでやはり単純に1つのスクリプトをさっと定期実行設定したい、という場合にはcronの方が簡単です。
システムを構築するような場合、きちんと設計したい場合には systemdを使ったほうが管理が簡単になる可能性はありますし、 より詳細に管理が出来ます。
ユーザーレベルジョブ
ユーザーレベルでの設定をsystemdで行うことも出来て、
~/.config/systemd/user/
ディレクトリにサービス/タイマーファイルを入れて、
$ systemctl --user enable myjob.timer
などとすればOK。
まとめ
cronジョブの代わりとしてsystemdを使おうと思った場合、 やはり少し覚えることも多く、敷居としては高い感じはしました。
その代わり詳細な時間設定や他のサービスとの連携もきちんと取れるようになるので、 システム管理として何らかのジョブを定期的に走らせたい、 という場合にはsystemdを使ったほうが便利だし、 慣れれば設定したり管理するのもむしろ楽になるかと思います。
システム管理をしよう、と思うくらいであればそれほど難しいものではないし いずれにしろ知っておかなくちゃいけないことだったりもするので。
macOSの方でも、cronジョブは使えますが、macOSの機能としてlaunchd
という
サービス管理をするシステムがあり、
これを使ってcron的な定期ジョブを実行することが出来ます。
これもsystemd同様、よりシステムに親和性の高い管理ができるという点で利点がありますが、 やはり必要な記述量が多いのでちょっとしきい値が高いものではあります。