【ITニュース解説】Stop Fighting cron: Practical systemd.timer Units on Linux
2026年10月09日に「Dev.to」が公開したITニュース「Stop Fighting cron: Practical systemd.timer Units on Linux」について初心者にもわかりやすく解説しています。
ITニュース概要
Linuxでの定期タスク実行は、従来のcronよりsystemd.timerが推奨される。timerで「いつ」、serviceで「何を」実行するか設定し、ログ管理、リソース制御、信頼性が向上。SEを目指す初心者が効率的にタスクを管理できる。
ITニュース解説
システムにおける定期的なタスクの実行は、ITインフラの安定稼働に不可欠な要素である。これまでLinux環境では、cronというツールがその役割を長く担ってきた。しかし、cronは単純な記述で手軽に利用できる反面、複雑なシステム運用においてはいくつかの課題を抱えている。例えば、指定時刻にマシンが停止していた場合、そのタスクは実行されずにスキップされることがある。複数のタスクが同時に実行されることによるリソース競合や、実行結果のログ管理が手動に依存するといった問題も生じやすい。さらに、タスクが期待通りに実行されたかどうかの確認も容易ではない。
このようなcronの限界に対し、現代のLinuxシステムではsystemd.timerユニットという、より洗練された解決策が提供されている。systemdはLinuxの起動プロセスやサービス管理を司る中心的なシステムであり、systemd.timerはその機能の一部として、定期実行タスクを効率的に管理するための仕組みである。
systemd.timerは「いつ」タスクを実行するかをスケジュールする役割を担い、これに対応するsystemd.serviceユニットが「何を」実行するか、つまり具体的な処理内容を定義する。例えば、「毎日午前2時にバックアップスクリプトを実行する」というタスクがある場合、foo.timerが「毎日午前2時」というスケジュールを管理し、foo.serviceが「バックアップスクリプトの実行」という処理を記述する。タイマーユニットが作動すると、対応するサービスユニットが起動され、タスクが実行される仕組みである。
このsystemd.timerを利用する最大の利点は、systemdの持つ豊富な機能を定期実行タスクにも適用できる点にある。例えば、systemdの統合ログシステムであるjournaldにより、タスクの実行ログが一元的に管理され、容易に検索・確認できる。また、サービスごとにリソース制限(メモリやCPUの使用量)やセキュリティ上のサンドボックス環境を設けることも可能である。これにより、タスク間の干渉を防ぎ、システムの安定性を高められる。さらに、systemdの強力な依存関係管理機能により、特定のサービスが起動した後でなければ実行しない、といった複雑な条件も設定できる。
systemd.timerには大きく分けて二つの種類がある。一つは**カレンダータイマー (OnCalendar=)**で、これは特定の壁時計時刻(年、月、日、時、分、秒、曜日、タイムゾーンなど)に基づいてタスクをスケジュールする。例えば、「毎日午前2時30分」や「毎週月曜日の午前9時」といった具体的な日時を指定できる。システムが停止していた間に実行時刻が過ぎてしまった場合でも、Persistent=trueオプションを設定しておけば、システムが再起動した際に遅れてタスクが一度実行されるため、重要なタスクの実行漏れを防げる。minutely、hourly、daily、weekly、monthlyといった便利な短縮形も用意されており、systemd-analyze calendarコマンドを使えば、記述したカレンダー式がどのように解釈され、次回の実行がいつになるかを確認できるため、誤設定を防ぐことが可能である。
もう一つは**モノトニックタイマー (OnBootSec=, OnUnitActiveSec=, OnStartupSec=)**で、これはシステムの起動後や関連するユニットが最後にアクティブになってからの相対的な時間に基づいてタスクをスケジュールする。壁時計の時間やタイムゾーンの影響を受けず、システムが稼働している間の時間間隔を基準とする。OnBootSec=5minと設定すれば、システム起動から5分後にタスクが実行され、OnUnitActiveSec=1hと設定すれば、対応するサービスが最後に実行されてから1時間後に再び実行される、といった具合である。これらのタイマーは、システム稼働時間に応じたメンテナンス作業などによく利用される。systemd-analyze timespanコマンドで時間間隔の指定を検証できる。
タイマーの挙動をさらに細かく制御するための重要なオプションも存在する。AccuracySec=はタイマーの精度を設定するもので、デフォルトでは1分に設定されている。これは電力消費を抑え、複数のタイマーの実行をまとめて効率化するためである。厳密な時刻に実行したい場合は、この値を小さく設定する必要がある。RandomizedDelaySec=は、タスクの実行時刻にランダムな遅延を加えるオプションで、多数のサーバーで同じタスクが同時に実行されるのを防ぎ、システム全体の負荷を分散させる効果がある。例えば、fstrim.timerのようなメンテナンス系タスクでよく用いられる。
systemdのバージョン257以降では、DeferReactivation=yesという便利なオプションが追加された。これは、タスクの実行時間がタイマーで設定された間隔よりも長くなってしまった場合に、次のタスクがすぐに連続して実行されてしまう「スタンプ問題」を防ぐためのものである。このオプションを設定すると、前のタスクが完了してから次の実行時刻が到来するのを待つようにスケジュールが調整される。
systemd.timerはシステム全体で管理されるタイマーだけでなく、特定のユーザーの環境下で動作するユーザータイマーも設定できる。これは~/.config/systemd/user/ディレクトリにユニットファイルを配置することで利用する。ユーザーがログインしていない状態でもタスクを実行させたい場合は、loginctl enable-linger "$USER"コマンドでユーザーのセッションを永続化させる設定が必要となる。
実際にsystemd.timerを使う際は、foo.timerとfoo.serviceという二つのファイルを通常作成し、systemctl daemon-reloadで変更を読み込み、sudo systemctl enable --now foo.timerコマンドでタイマーを有効化し、即座に起動する。サービスユニット自体を直接起動するのではなく、必ずタイマーユニットを起動する点が重要である。タスクの実行状況はsystemctl list-timersやjournalctl -u foo.service、journalctl -u foo.timerコマンドで確認できる。
cronとsystemd.timerを比較すると、systemd.timerは、電源オフ時のタスク実行漏れをPersistent=trueで解消し、journaldによる統一されたログ管理、cgroupによる詳細なリソース制限、systemdのユニットグラフに基づく強力な依存関係管理、RandomizedDelaySec=による負荷分散といった点で優れている。また、systemd-analyze calendarやsystemd-analyze timespanといったコマンドにより、スケジュールの設定が正しいか事前に検証できるため、テストとデバッグが非常に容易である。
systemdにはタイマー以外にも、ファイルシステムの変更を監視する.pathユニットや、ネットワーク接続を監視する.socketユニットなど、様々なイベントに基づいてサービスを起動する仕組みがある。一時的に特定のタスクをスケジュールして実行したい場合には、ユニットファイルをディスクに作成せずにsystemd-runコマンドを利用することも可能である。
systemd.timerを導入することで、従来のcronが抱えていた多くの課題を解決し、より堅牢で管理しやすいシステム運用を実現できる。特に、複数のサーバーで同じタスクを実行するような環境や、複雑な依存関係を持つタスクを扱う場合には、systemd.timerの利用が強く推奨される。タスクのスケジュールはタイマーに任せ、具体的な処理はサービスとして記述することで、システムの信頼性と運用効率を大幅に向上させることができるだろう。