PR

【Ubuntu】Systedのtimer機能でタスクを定期的に実行する方法

「Ubuntu」で「systemd」の「timer」機能を使って、「cron」のように時間を指定してタスクを実行させる方法を紹介します。

「cron」よりも柔軟な設定が可能で、システムとの連携もスムーズに行えるのでとても便利です。

systemdのtimer機能とは?

「systemd」には「timer」という機能が搭載されていて、「cron」と同様に指定した日時に特定のタスクを実行することができます。

「cron」との主な違いは以下の通りです。

  • systemdとの連携: systemdの一部として動作するため、サービスの起動や停止と連携しやすい
  • 柔軟な設定: 日時指定だけでなく、特定のイベント発生時にタスクを実行するなど、より柔軟な設定が可能
  • ログ管理: systemdのjournaldによるログ管理が容易

timerの基本的な使い方

「systemd」の「timer」機能を使用するには、以下の2つのファイルを作成する必要があります。

  1. serviceファイル (.service): 実行するタスクを定義
  2. timerファイル (.timer): タスクを実行する日時や条件を定義

serviceファイル (.service)の作成例

はじめに実行したいタスクを定義するserviceファイルを作成します。

例として、「/var/log/syslog」に「test mesage.」というメッセージを記録するタスクを実行するサービスファイルを作成します。

$ sudo vi /etc/systemd/system/timer_test.service

ファイルの内容は以下のとおりです。

「#」以降のコメント文は説明の為に記述しているので、実際のファイルには記述しないで下さい。

[Unit]
Description=timer test service  # サービスの説明

[Service]
Type=oneshot    # 1度だけタスクを実行
ExecStart=/usr/bin/logger "test message."   # サービス起動時に実行するコマンド

[Install]
WantedBy=multi-user.target    # サービスを有効にするターゲットを指定

timerファイル (.timer)

serviceファイルが完成したら、次にタスクを実行する日時や条件を定義するtimerファイルを作成します。

$ sudo vi /etc/systemd/system/timer_test.timer

毎時「05分,10分,15分,20分...」といったように5分毎に「timer_test.service」を実行させる場合は、以下のように記述します。

「#」以降のコメント文は説明の為に記述しているので、実際のファイルには記述しないで下さい。

[Unit]
Description=Run timer_test.service every 5 minutes   # タイマーの説明

[Timer]
OnCalendar=*:0/5           # 5分ごとに実行
Unit=timer_test.service    # 実行するサービスファイル

[Install]
WantedBy=timers.target     # タイマーを有効にするターゲットを指定

timerの起動と自動起動設定

「systemd」の設定ファイルを再読込し、作成したserviceファイルと、timerファイルを認識させます。

$ sudo systemctl daemon-reload

作成したタイマーを起動します。

$ sudo systemctl start timer_test.timer

タイマーがサーバ起動時に自動起動する設定を行います。

$ sudo systemctl enable timer_test.timer

タイマーの起動状態確認

「systemctl list-timers」コマンドで、システムに登録されているタイマーの一覧と以下の情報が表示されます。

  • NEXT: 次にタイマーが起動する日時
  • LEFT: 次にタイマーが起動するまでの残り時間
  • LAST: 最後にタイマーが起動した日時
  • PASSED: 最後にタイマーが起動してから経過した時間
  • UNIT: timerユニットの名前
  • ACTIVATES: タイマーが起動時に実際に実行されるサービスの名前
$ sudo systemctl list-timers

タイマーを指定すると、その情報のみを表示させることもできます。

$ sudo systemctl list-timers timer_test.timer
NEXT                            LEFT LAST                             PASSED UNIT             ACTIVATES         
Thu 2025-04-03 14:20:00 JST 2min 50s Thu 2025-04-03 14:15:01 JST 2min 8s ago timer_test.timer timer_test.service

1 timers listed.
Pass --all to see loaded but inactive timers, too.

今回は「/var/log/syslog」にログを出力させるサービスをタイマーで定義しているので、下記のように「/var/log/syslog」を確認するとタイマーで指定した時間にログが出力されていることが確認できます。

$ sudo cat /var/log/syslog
### 中略 ###
2025-04-03T14:40:01.851164+09:00 xxxxx root: test message.
2025-04-03T14:40:01.852224+09:00 xxxxx systemd[1]: timer_test.service: Deactivated successfully.
2025-04-03T14:40:01.852639+09:00 xxxxx systemd[1]: Finished timer_test.service - timer test service.

timerの停止方法

タイマーを一時的に停止するには、以下のコマンドを実行します。

一時停止

「systemctl stop」でタイマーを停止すると、再度startさせるか、ホストを再起動するまではタイマーは停止します。

$ sudo systemctl stop timer_test.timer

無効化

タイマーを無効化して停止するには、「systemctl disable」で自動起動設定も無効化しておく必要が有ります。

$ sudo systemctl stop timer_test.timer
$ sudo systemctl disable timer_test.timer
Removed "/etc/systemd/system/timers.target.wants/timer_test.timer".

停止確認

「systemctl list-timers」コマンドで確認を行い、設定していたtimerが表示されない確認します。

$ sudo systemctl list-timers timer_test.timer
NEXT LEFT LAST PASSED UNIT ACTIVATES

0 timers listed.

「systemctl status」コマンドで確認することもできます。

タイマーが停止している場合は、Activeの項目がActive: inactive (dead) となっています。

$ sudo systemctl status timer_test.timer
○ timer_test.timer - Run timer_test.service every 5 minutes
     Loaded: loaded (/etc/systemd/system/timer_test.timer; enabled; preset: enabled)
     Active: inactive (dead) since Fri 2025-04-04 09:35:32 JST; 1min 51s ago
   Duration: 39.701s
    Trigger: n/a
   Triggers: ● timer_test.service

Apr 04 09:34:52 xxxxxx systemd[1]: Started timer_test.timer - Run timer_test.s>
Apr 04 09:35:32 xxxxxx systemd[1]: timer_test.timer: Deactivated successfully.
Apr 04 09:35:32 xxxxxx systemd[1]: Stopped timer_test.timer - Run timer_test.s>

timerファイルの設定

timerファイルの各セクションについて説明します。

  • Unitセクション
  • Timerセクション
  • Installセクション

[Unit]セクション

[Unit]セクションでは、一般的な情報や依存関係を記述します。

普段使うことが多そうな項目を紹介しますので、必要なものだけ指定して設定を行ってください。

  • Description: タイマーの説明
  • After: 指定されたユニットが起動した後にタイマーを起動
  • Before: 指定されたユニットが起動する前にタイマーを停止
  • Conflicts: 指定されたユニットと同時に起動しないようにする

「Description」は、タイマーで何が実行されているのかが分かりやすくなりますので、管理上設定をしておくことをおすすめします。

[Timer]セクション

[Timer]セクションでは、タイマーのスケジュールや動作に関する設定を記述します。

普段使用しそうな設定を抜粋して紹介します。

  • OnCalendar: タイマーを起動する日時をカレンダー形式で指定
  • OnBootSec: システム起動後の経過秒数でタイマーを起動
  • OnStartupSec: systemdタイマーが開始してからの経過秒数でタイマーを起動
  • OnUnitActiveSec: 関連づけられたserviceが起動してからの経過秒数でタイマーを起動
  • OnUnitInactiveSec: 関連づけられたserviceが停止してからの経過秒数でタイマーを起動
  • AccuracySec: タイマーの精度を秒単位で指定
  • RandomizedDelaySec: タイマー起動時間にランダムな遅延を追加
  • Persistent: システム停止中にタイマーの起動時刻が来た場合に、次回起動時にタイマーを実行するかどうかを指定

cronと同じ様にスケジュールの設定を行いたい場合は「OnCalendar」を使用し、より厳密に実行時間を指定したい場合は「AccuracySec=0」もあわせて設定してください。

[Install]セクション

[Install]セクションでは、タイマーユニットを有効にするための設定を記述します。

  • WantedBy: タイマーユニットを有効にするターゲットを指定

通常は「WantedBy=timers.target」と指定します。

OnCalendarでのスケジュール設定方法

OnCalendarでスケジュールを設定する場合は、以下のように記述します。

OnCalendar=年-月-日 時:分:秒

曜日を指定をする場合は、以下のように記述します。

OnCalendar=曜日 年-月-日 時:分:秒

各項目は以下の範囲で設定することが出来ます。

  • 曜日: Mon、Tue、Wed、Thu、Fri、Sat、Sun (省略可能)
  • 年: 任意の年 (省略可能)
  • 月: 1〜12 (省略可能)
  • 日: 1〜31 (省略可能)
  • 時: 0〜23
  • 分: 0〜59
  • 秒: 0〜59 (省略可能)

その他にも、以下の指定方法も使用することが出来ます。

  • * : 全ての値(ワイルドカード)
  • */n : 間隔(nは間隔の数字)
  • a..b : aからbの範囲
  • a,b,c : のいずれかを満たす場合

月末の指定方法

以下のように「~」(チルダ)を使うと、月末から何日か指定することができます。

  • *-*~01 00:00:00 :月末のAM0時
  • *-*~03 00:00:00 :月末から3日前のAM0時
  • Mon *-*~07/1 00:00:00月の最終月曜日のAM0時

OnCalendar設定例

次に、OnCalendarでのスケジュール設定例を紹介します。

【定期実行】毎日午前0時に実行

年月日をすべて「*」と指定し、時間を「00:00:00」(午前0時)と設定することで、毎日午前0時にスケジュールされたタスクを実行します。

OnCalendar=*-*-* 00:00:00

年月日と秒を省略した省略形は、次のようになります。

OnCalendar=0:0

【日にち指定】毎月1日の午前0時に実行

OnCalendar=*-*-1 00:00:00

【曜日指定】毎週月曜日のAM9時に実行

曜日を指定をする場合は、以下のように記述します。

OnCalendar=Mon *-*-* 09:00:00
OnCalendar=Mon 09:00      # 省略形

【間隔指定】10分毎に実行

「/」を使うと実行したい間隔を設定することが出来ます。

以下の場合、毎時「00分、10分、20分、30分、40分、50分」の10分おきに、スケジュールされたタスクを実行します。

OnCalendar=*-*-* *:00/10:00
OnCalendar=*:00/10        # 省略形

00分以外を始まりとした間隔指定

以下の場合、毎時「02分、12分、22分、32分、42分、52分」の10分おきに、スケジュールされたタスクを実行します。

OnCalendar=*-*-* *:02/10:00

【範囲指定】平日(月〜金曜日)AM4時に実行

「..」で実行したい範囲を指定します。

月曜から金曜日の範囲を指定する場合は、「Mon..Fri」と指定します。

OnCalendar=Mon..Fri *-*-* 04:00:00

【どれか一方の条件に合致】月、水、金曜日のAM4時に実行

「,」で区切って、実行したい条件を指定します。

月、水、金曜日を指定するのであれば「Mon,Wed,Fri」と設定します。

OnCalendar=Mon,Wed,Fri *-*-* 04:00:00

【複合設定】平日の午前1,3,5時の「00分,30分」に実行

これまで紹介してきた、「間隔指定」「範囲指定」「どれか一方の条件に合致」を複合して設定することも出来ます。

OnCalendar=Mon..Fri *-*-* 01,03,05:00/30:00

その他の設定方法

年月日や日時の設定方法は他にも色々とあるので、以下のページを参照してみてください。

https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html#Calendar%20Events

systemd-analyze calendar スケジュール設定の確認

「systemd-analyze calendar」コマンドに「OnCalendar」で設定した値を渡してあげると、そのスケジュールが具体的にどのような日時を指定しているのか確認を行うことが出来ます。

$ systemd-analyze calendar "OnCalendar設定内容"

実際に、毎日AM0時に実行するという内容である「*-*-* 00:00:00」の確認を行ってみます。

「Next elapse」に次回の実行日時が表示され、「From now」には残り時間が表示されます。

$ sudo systemd-analyze calendar "*-*-* 00:00:00"
Normalized form: *-*-* 00:00:00
    Next elapse: Sat 2025-04-05 00:00:00 JST
       (in UTC): Fri 2025-04-04 15:00:00 UTC
       From now: 6h left

省略形で確認を行うと、「Normalized form」で省略していない形が表示されます。

$ sudo systemd-analyze calendar "0:0"
  Original form: 0:0
Normalized form: *-*-* 00:00:00
    Next elapse: Sat 2025-04-05 00:00:00 JST
       (in UTC): Fri 2025-04-04 15:00:00 UTC
       From now: 6h left

日時の設定方法が間違っている場合は、下記のように間違っているという旨のメッセージが表示されます。

$ sudo systemd-analyze calendar "Man *-*-* 00:00:00"
Failed to parse calendar specification 'Man *-*-* 00:00:00': Invalid argument

コメント

タイトルとURLをコピーしました