systemd/タイマー

提供: ArchWiki
ナビゲーションに移動 検索に移動

関連記事

タイマーは名前が .timer で終わる systemd のユニットファイルであり、.service ファイルやイベントを制御します。cron の代わりとしてタイマーを使うことができます (#cron を置き換える を読んで下さい)。タイマーにはカレンダー時刻のイベントとモノトニック時刻のイベントのサポートが入っており、さらに非同期に実行することも可能です。

タイマーユニット

タイマーは拡張子が .timersystemd のユニットファイルです。他の ユニット設定ファイル と似ていますが特別に [Timer] セクションが存在します。[Timer] セクションにはタイマーが作動する時間と処理を定義します。タイマーには2つのタイプがあり、どちらか一つを使って定義されます:

  • モノトニックタイマー は刻々と変わる開始点と相応したタイムスパンの後に作動します。様々なモノトニックタイマーが存在しますがどれも次のような形式です: OnTypeSec= OnBootSecOnActiveSec は全てのモノトニックタイマーで共通です。
  • リアルタイムタイマー (別名ウォールクロックタイマー) は (cron のジョブと同じように) カレンダーイベントにあわせて作動します。OnCalendar= オプションを使って定義を行います。

タイマーのオプションについては systemd.timer(5)man ページ で説明されています。カレンダーイベントやタイムスパンの引数構文については systemd.time(7)man ページ で説明されています。

ノート: systemd は、ブート後にアクティブにする必要があるすべてのタイマーを設定するターゲット timers.target を提供します (詳細については、systemd.special(7) を参照してください) これを使用するには、タイマーの [Install] セクションに WantedBy=timers.target を追加し、タイマーユニットを 有効化 します。

サービスユニット

それぞれの .timer ファイルには、対応する .service ファイルが存在します (例: foo.timerfoo.service)。.timer ファイルは .service ファイルを作動・制御します。.service[Install] セクションは必要ありません。有効にするのは timer ユニットだからです。必要ならば、タイマーの [Timer] セクションで Unit= オプションを使うことで別の名前のユニットを制御することもできます。

管理

timer ユニットを使用するには、他のユニットと同じように有効化・起動します。起動しているタイマーを全て表示するには、次を実行:

$ systemctl list-timers
NEXT                          LEFT        LAST                          PASSED     UNIT                         ACTIVATES
Thu 2014-07-10 19:37:03 CEST  11h left    Wed 2014-07-09 19:37:03 CEST  12h ago    systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Fri 2014-07-11 00:00:00 CEST  15h left    Thu 2014-07-10 00:00:13 CEST  8h ago     logrotate.timer              logrotate.service
ノート:
  • (有効でないタイマーも含めて) 全てのタイマーを確認したい場合、systemctl list-timers --all を使って下さい。
  • タイマーによって実行するサービスの状態は、今現在作動しているのでない限り、inactive になります。
  • タイマーがズレる場合は、/var/lib/systemd/timers もしくは ~/.local/share/systemd/ にある stamp-* ファイルを削除してみてください。stamp ファイルはタイマーが実行された最後の時刻を記録しており、ファイルを削除することでタイマーの次の作動時に systemd が再構成を行います。

サンプル

タイマーを使用してサービスを実行するのにあたって、service ユニットファイルに変更を加える必要はありません。以下の例では foo.timer という名前のタイマーを使って foo.service を定期的に実行します。

モノトニックタイマー

起動15分後に実行され、システムが起動している間、一週間ごとに再度実行されるタイマー:

/etc/systemd/system/foo.timer
[Unit]
Description=Run foo weekly and on boot

[Timer]
OnBootSec=15min
OnUnitActiveSec=1w 

[Install]
WantedBy=timers.target

リアルタイムタイマー

一週間ごとに起動するタイマー (月曜日の午前12:00に実行)。システムの電源が切られていたなどの理由で、最後の起動時間を過ぎていた場合、すぐに実行されます (Persistent=true オプション):

/etc/systemd/system/foo.timer
[Unit]
Description=Run foo weekly

[Timer]
OnCalendar=weekly
Persistent=true     
 
[Install]
WantedBy=timers.target

もっと細かく日時を指定する必要がある場合、次の形式で OnCalendar イベントを制御できます: DayOfWeek Year-Month-Day Hour:Minute:Second。アスタリスクをワイルドカードとして使うことができ、カンマで複数の日時を指定することができます。値を .. で区切ることで連続的に日程を指定することも可能です。

例えば、以下の場合、毎月の1日から4日まで、月曜日か火曜日の場合にのみ、午後0時にサービスを実行します:

OnCalendar=Mon,Tue *-*-01..04 12:00:00

毎月第1土曜日にサービスを実行したい場合は以下のようになります:

OnCalendar=Sat *-*-1..7 18:00:00

毎朝4時に実行したい場合は以下のようになります:

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

OnCalendar は複数指定でき、複数の異なるタイミングでサービスを実行できます。次の例では、平日の22:30および土日の20:00に実行されます:

OnCalendar=Mon..Fri 22:30
OnCalendar=Sat,Sun 20:00

ディレクティブの最後にタイムゾーンを指定することもできます (受け入れられる値をリストするには、timedatectl list-timezones を使用します。)

OnCalendar=*-*-* 02:00:00 Europe/Paris

詳しくは systemd.time(7) を見てください。

ヒント:
  • OnCalendar の日時の指定方法は systemd-analyze ユーティリティの calendar オプションを使用することでテストすることができます。タイマーユニットで使用したときに次に実行される日時も確認できます。例えば、systemd-analyze calendar weeklysystemd-analyze calendar "Mon,Tue *-*-01..04 12:00:00" のようにコマンドを実行することでテストできます。
  • libfaketime でインストールできる faketime コマンドを使うと、これらのコマンドを使ったいろいろなシナリオをテストするのに便利です。
  • dailyweekly などの特殊なイベントの表現は特定の起動時間を示しているため、同じカレンダーイベントが設定されているタイマーがあった場合、同時に起動します。そのようなことが発生すると、タイマーのサービスがシステムリソースを取り合って、システムパフォーマンスが落ち込む可能性があります。このような問題は RandomizedDelaySec オプションを使用してタイマーの起動時間を散らすことで解決できます。systemd.timer(5) を参照してください。
  • AccuracySec のデフォルト値 1m の不正確さを避けるために、オプション AccuracySec=1us を [Timer] セクションに追加します。systemd.timer(5) も参照してください。
  • 一部のオプション (WakeSystem) は、特定のシステム機能を必要とし、タイマーの開始を妨げる場合があり、その結果、次のエラーメッセージが表示されます: "Failed to enter waiting state: Operation not supported" そして "Failed with result 'resources'."

一時的な .timer ユニット

systemd-run を使うことで一時的な .timer ユニットを作ることができます。サービスファイルを作成しなくても、特定時刻にコマンドが実行されるように設定することが可能です。例えば、以下のコマンドは30秒後にファイルを作成します:

# systemd-run --on-active=30 /bin/touch /tmp/foo

タイマーファイルが存在しない既存のサービスファイルを指定することもできます。例えば、以下のコマンドは12.5時間後に someunit.service という名前の systemd ユニットを起動します:

# systemd-run --on-active="12h 30m" --unit someunit.service

詳しくは systemd-run(1) を見てください。

cron を置き換える

おそらく一番有名なジョブスケジューラは cron ですが、systemd のタイマーはその代替手段になりえます。

メリット

タイマーを使う主要なメリットは、それぞれのジョブが固有の systemd サービスを使うというところに根ざします。そのメリットには以下のようなものがあります:

  • タイマーとは別個にジョブを実行することが簡単にできます。これによってデバッグが楽になります。
  • 特定の環境で動作するようにジョブを設定することができます (systemd.exec(5) man ページを参照)。
  • ジョブを cgroups の支配下に置けます。
  • 他の systemd ユニットに依存するようにジョブを設定できます。
  • systemd の journal でジョブが記録されるのでデバッグが簡単です。

注意事項

cron では簡単にできることが、タイマーユニットを使用する場合、難しかったり不可能であったりすることがいくつか存在します。

  • 冗長性: systemd を使って定期的なジョブを設定するには2つのファイルを作成して2回 systemctl コマンドを実行します。それに対して crontab には一行を追加するだけです。
  • メール: ジョブが失敗した時にメールを送信する cron の MAILTO と同等なものは存在しません。ただし各サービスに OnFailure= オプションを使うことで同じような機能を設定することはできます。

MAILTO

Cron の MAILTO のように、systemd で、ユニットが失敗したときにメールを送信するように設定できます。それにはまず2つのファイルが必要です: メールを送信するための実行可能ファイルと、実行可能ファイルを起動するための .service。以下の例では、sendmail (smtp-forwarder を含むパッケージにはすべて含まれています) を使用するシェルスクリプトが実行可能ファイルになっています:

/usr/local/bin/systemd-email
#!/bin/bash

/usr/bin/sendmail -t <<ERRMAIL
To: $1
From: systemd <root@$HOSTNAME>
Subject: $2
Content-Transfer-Encoding: 8bit
Content-Type: text/plain; charset=UTF-8

$(systemctl status --full "$2")
ERRMAIL

どんな実行可能ファイルを使うのであれ、上記のシェルスクリプトのように、最低でも2つの引数が必要になります: 送信先のアドレスと状態を取得するユニットファイルです。以下の .service はそれらの引数を渡します:

/etc/systemd/system/status-email-user@.service
[Unit]
Description=status email for %i to user

[Service]
Type=oneshot
ExecStart=/usr/local/bin/systemd-email address %i
User=nobody
Group=systemd-journal

user はメールを送信するユーザーに、address はユーザーのメールアドレスに置き換えてください。受信者はハードコードされますが、インスタンスパラメータとしてユニットファイルを渡すことで、上記のサービスだけで他のユニットのメールも送ることができます。status-email-user@dbus.service起動して、メールが受け取れることを確認してください。

問題ないようでしたら、メールを送って欲しいユニットの [Unit] セクションに OnFailure=status-email-user@%n.service を追加してください。%n はユニットの名前をテンプレートに指定します。

ノート:
  • SSMTP#セキュリティ にしたがって SSMTP を設定した場合、ユーザー nobody/etc/ssmtp/ssmtp.conf にアクセスすることができず、systemctl start status-email-user@dbus.service コマンドは失敗します。status-email-user@.service モジュールの User に root を使うことでこれを回避できます。
  • メールスクリプトで mail -s somelogs address を使用すると、mail はフォークして、systemd はスクリプトの終了を確認したときに mail プロセスを終了します。mail -Ssendwait -s somelogs address として mail がフォークしないようにしてください。

crontab を使用する

crontab を使って定期的なサービスを管理するツールとして systemd-cron-nextAURsystemd-cronAUR があります。どちらも AUR からインストールすることができます。これらのツールには systemd に存在しない MAILTO 機能が実装されています。

もし、スケジュールされたジョブをまとめて見れるから crontab が好きだという場合は、systemctl でそれと同じことが可能です。#管理 を見て下さい。

手動で行う

既存の crontab から移行する以外に、cron と同じ周期を使用することが望ましい場合があります。定期的に開始する各サービスのタイマーを作成するという面倒な作業を回避するには、テンプレートユニット を使用します。例:

/etc/systemd/system/monthly@.timer
[Unit]
Description=Monthly Timer for %i service

[Timer]
OnCalendar=*-*-1 02:00:00
AccuracySec=6h
RandomizedDelaySec=1h
Persistent=true
Unit=%i.service

[Install]
WantedBy=default.target
ノート: タイマーの起動によってすべてのユニットが同時に開始されるのを避けるために、AccuracySec だけでなく RandomizedDelaySec を使用する重要性については、systemd.timer(5) § OPTIONS を参照してください。

その後、monthly@unit_name.timer起動/有効化 行うだけで済みます。

ヒント: テンプレートユニットはネストできます。たとえば、monthly@btrfs-scrub@mnt-$(systemd-escape bbb76c63-e4ac-4e39-8897-a120c5d30686).timer起動/有効化 することが出来ます。

"有効期間" の処理

一部のソフトウェアは、最後に実行されてからの経過時間を追跡します。たとえば、最後のダウンロードが 24 時間以内に終了した場合はデータベースの更新をブロックします。

デフォルトでは、タイマーは起動したタスクがいつ終了したかを追跡しません。これを回避するには、OnUnitInactiveSeconds を使用できます:

/etc/systemd/system/daily-inactive@.timer
[Unit]
Description=Launch %i service 24hours after it deactivated

[Timer]
OnUnitInactiveSec=1day1sec
Unit=%i.service
Persistent=true

[Install]
WantedBy=default.target
ヒント: Restart=on-failureRestartSec を併用すると、失敗と成功の後に異なるスケジュールに従ってユニットを再実行することができます。systemd.service(5) § OPTIONS を参照して下さい。

参照

  • systemd.timer(5)
  • Fedora Project wikisystemd カレンダータイマーのページ
  • Gentoo wikisystemd タイマーサービスのセクション
  • systemd-cron-next — crontab と anacrontab ファイルからタイマーとサービスを生成するツール
https://github.com/systemd-cron/systemd-cron-next || systemd-cron-nextAUR
  • systemd-cron — cron スクリプトを実行する systemd ユニットが入っています。systemd-crontab-generator を使って crontab を変換。
https://github.com/systemd-cron/systemd-cron || systemd-cronAUR