ジョブスケジューリングとは

Linuxには、コマンドやスクリプトを指定した時刻・間隔で自動実行する仕組みがいくつか用意されています。目的によって使い分けが必要で、大きく次の系統に分かれます。

仕組み・機能説明
cron「毎日3時に」「毎週月曜の9時に」のように、繰り返し実行するジョブのためのスケジューラです。システムが常時稼働していることを前提としています。
at「今日の22時に1回だけ」のように、繰り返さない単発のジョブを予約する仕組みです。
anacroncronと似た定期実行の仕組みですが、ノートPCのように常時電源が入っているとは限らないシステムでも、電源が入っていなかった間に実行できなかったジョブを後から埋め合わせて実行できる点が異なります。
systemdのタイマーユニットsystemdが提供する比較的新しい仕組みで、cron・anacron双方の役割を、.timerという単位でまとめて扱えるように設計されています

本記事では、この4つの仕組みについて、代表的な設定ファイル・コマンドを解説します。


cronによる定期実行

crontab(コマンドと書式)

画像

各ユーザーは、自分専用の定期実行スケジュール(crontab)をcrontabコマンドで管理します。

オプション説明
-e現在のユーザーのcrontabを編集(EDITOR・VISUAL環境変数で指定されたエディタが起動)
-l現在のユーザーのcrontabの内容を表示
-r現在のユーザーのcrontabを削除
-u ユーザー名操作対象のユーザーを指定。rootが他のユーザーのcrontabを操作する場合に使用

ユーザーのcrontabの各行は、空白で区切る5個の時刻フィールド(分・時・日・月・曜日)と、その後に続く実行するコマンド欄で構成されます。コマンド欄は行末までが対象であり、コマンドの引数などの空白を含められます。

# 分 時 日 月 曜日 コマンド
30 2 * * * /usr/local/bin/backup.sh
  • 分(0-59)・時(0-23)・日(1-31)・月(1-12)・曜日(0-7、0と7はどちらも日曜日)の5つのフィールドには、*(すべての値に一致)、,(複数値の列挙)、-(範囲)、/(間隔、例:*/15で15分おき)が使えます。
  • 日と曜日の両方を*以外で指定した場合は、一般的なcronでは両方に一致する必要はなく、日または曜日のどちらか一方に一致すると実行されます。
  • 一部の実装Vixie cron系列の実装によく見られる拡張で、標準の書式ではありません[1]では、この5フィールドの代わりに@daily・@rebootのような特殊文字列を使うこともできますが、すべてのcron実装で使えるとは限らない点に注意してください。

/var/spool/cron/

ユーザーごとのcrontabの実体(crontab -eで編集した内容)が保存されるディレクトリです。ユーザー名にちなんだファイル名で保存されます。具体的な配置(/var/spool/cron/crontabs/のようにさらにサブディレクトリを持つか等)はディストリビューションによって異なります。[2]このファイルを直接エディタで編集することは推奨されませんcrontabコマンドを経由しないと、権限設定やcronデーモンへの反映が正しく行われない場合があります[3]。

/etc/crontab

画像

/etc/crontabはシステム全体で共有される、管理者用のcrontabファイルです。ユーザーのcrontabと異なり、時刻を表す5フィールドの直後に、どのユーザー権限で実行するかを指定するフィールドが追加され、その後にコマンド欄が続きます。コマンド欄は行末までが対象であり、空白を含められます。

# 分 時 日 月 曜日 実行ユーザー コマンド
25 6 * * * root run-parts --report /etc/cron.daily

/etc/cron.{d,daily,hourly,monthly,weekly}/

これらは多くのディストリビューションで利用される、定期実行に関連するディレクトリ群ですが、中身の性質が異なる2種類に分かれます。ディレクトリの有無や呼び出し方は、ディストリビューションの構成によって異なります。

  • /etc/cron.d/:/etc/crontabと同じく、時刻を表す5フィールド、実行ユーザー、コマンド欄から成る形式のスニペットファイルを置くディレクトリです。パッケージのインストール時に、/etc/crontab本体を書き換えずに定期実行ジョブを追加する目的でよく使われます。
  • /etc/cron.daily/・/etc/cron.hourly/・/etc/cron.monthly/・/etc/cron.weekly/:crontab形式の設定ファイルではなく、実行権限が付与されたファイル(通常はスクリプト)を置くディレクトリです。これらのディレクトリ内のファイルは、run-partsというコマンドによって、ファイル名の条件を満たすものがまとめて実行されます対象となるファイル名の条件はrun-partsの実装によって異なります。[4]。この呼び出し自体は、多くのディストリビューションで/etc/crontab(前述の例のような1行)や、後述するanacronによって行われます。

/etc/cron.allow, /etc/cron.deny

画像

/etc/cron.allowや/etc/cron.denyはcrontabコマンドを使える一般ユーザーを制限するためのファイルです。両方とも、1行に1ユーザー名を記載します。判定の優先順位は次のとおりです。

  1. /etc/cron.allowが存在する場合:このファイルに記載されているユーザーのみがcrontabコマンドを使えます(/etc/cron.denyの内容は無視されます)。
  2. /etc/cron.allowが存在せず、/etc/cron.denyが存在する場合:このファイルに記載されていないユーザーがcrontabコマンドを使えます。
  3. どちらのファイルも存在しない場合:crontabコマンドを使えるユーザーの既定値は、cron実装やディストリビューションの設定によって異なります。rootのみを許可する構成もあれば、全ユーザーを許可する構成もあります。

atによる1回限りの実行

at

atは、指定した日時に1回だけコマンドを実行するようスケジュールするコマンドです。対話的に実行するコマンドを入力し、Ctrl+Dで入力を終えるとジョブが登録されます。

$ at 22:00
at> /usr/local/bin/one-shot-task.sh
at> <EOT>

日時の指定方法には、at 10:00(今日または明日の10時)、at now + 5 minutes(現在時刻から5分後)、at teatimeのような柔軟な表現が使えます受け付けられる日時の書式の詳細は、atの実装(多くのディストリビューションではatパッケージ、内部的にatdデーモンが実行を担います)によって細部が異なる場合があります。[5]。

atq

現在キューに入っている(まだ実行されていない)自分のジョブの一覧を表示するコマンドです(at -lでも同じ結果が得られます)。rootが実行した場合は、全ユーザーのジョブが表示されます。

atrm

指定したジョブ番号(atqの出力に表示される番号)のジョブを、実行される前に取り消すコマンドです。

/etc/at.allow, /etc/at.deny

atコマンドを使える一般ユーザーを制限するファイルです。ファイル名・判定の優先順位は、前述の/etc/cron.allow・/etc/cron.denyと同じ考え方です。at.allowが存在すればそちらが優先され、at.allow・at.denyがどちらも存在しない場合にatコマンドを使えるユーザーの既定値は、at実装やディストリビューションの設定によって異なります。cron用の許可・拒否設定とat用の許可・拒否設定は別々のファイルで管理されており、片方を許可してももう片方には影響しません。

anacronによる非常時対応の定期実行

anacron

画像

anacronは、cronと同様に定期実行のジョブを扱いますが、システムが24時間365日稼働していることを前提としない点が異なります。cronは、実行されるはずだった時刻にシステムの電源が入っていなければ、そのジョブは実行されずに終わってしまいます。anacronは、電源が入っていなかった間に実行できなかったジョブがあれば、次にanacronが実行されたときに、実行期限を過ぎたジョブを1回実行します。この特性から、ノートPCやデスクトップPCのように、常時電源が入っているとは限らないシステム向けの仕組みとして位置づけられています。

anacronが扱えるのは日単位の粒度(1日単位・週単位・月単位に相当する日数)のジョブに限られ、cronのように「毎時」「特定の分」といった細かい間隔の指定はできません。

多くのディストリビューションでは、前述の/etc/cron.daily/・/etc/cron.weekly/・/etc/cron.monthly/ディレクトリの実行そのものをanacronが担当するよう構成されており、cron自体が直接run-partsを呼び出すとは限りませんanacronパッケージがインストールされていない場合や、ディストリビューションの構成によっては、/etc/crontab側が直接run-partsを呼び出す従来通りの構成になっていることもあります。「どの環境でも必ずanacron経由である」とは断定できません。[6]。

/etc/anacrontab

anacronのジョブを定義する設定ファイルです。1行は、空白で区切るperiod・delay・job-identifierの3フィールドと、その後に続くcommand欄で構成されます。command欄は行末までが対象であり、空白を含められます。

# period delay job-identifier command
7 25 cron.weekly run-parts --report /etc/cron.weekly
  • period(周期、日数):何日おきに実行するかを指定します。
  • delay(遅延、分):anacronがそのジョブを実行すると判断してから、実際に実行を始めるまでの待機時間です。多数のジョブが一斉に走って負荷が集中するのを避ける目的で使われます。
  • job-identifier(ジョブ識別子):ジョブを一意に識別する名前です。anacronは、このジョブが最後にいつ実行されたかを別途記録しておき、この記録と現在日時を比較することで「period日数以内に実行済みかどうか」を判定します。
  • command(コマンド):実際に実行するコマンドです。

systemdによるタイマー管理

systemctl(タイマーユニット関連)

画像

systemdは、cron・atの代替となる仕組みとして、.timerという種類のユニットを提供しています。タイマーユニットは、同じ名前の.serviceユニット(例:backup.timerはbackup.service)と対で使うのが基本です。タイマー自体には「いつ実行するか」だけを定義し、実際に実行する処理は対応する.serviceユニット側に書きます。

タイマーの指定方法には、大きく2種類あります。

  • OnCalendar=:Mon *-*-* 03:00:00のような、実時刻(カレンダー時刻)に基づく指定です。停止中に逃した実行を補う設定は、後述するPersistent=trueです。
  • OnBootSec=・OnUnitActiveSec=等:システム起動時や、前回そのユニットが活動した時点からの経過時間に基づく指定(相対時刻)です。実時刻とは無関係に、経過時間だけで判定されます。システム休止中でも指定時刻に起床させるには、WakeSystem=trueの設定が必要です。

Persistent=trueを設定すると、OnCalendar=のタイマーが本来発火するはずだった時刻にシステムが停止していた場合、次にタイマーユニットが有効になったときに一度だけ実行を行います。通常は有効なタイマーが次回起動時に開始されるため、これは前述のanacronの「実行できなかった分を後から埋め合わせる」という特性と同じ考え方を、systemdのタイマーで実現する設定です。

タイマーユニットの有効化・確認には、他のsystemdユニットと同じくsystemctlを使います。

  • systemctl enable --now バックアップ.timer:タイマーを次回起動時にも有効になるよう登録し、即座に開始します。
  • systemctl list-timers:現在アクティブなタイマーユニットの一覧を、次回実行予定時刻とあわせて表示します。
  • systemctl status バックアップ.timer:特定のタイマーユニットの状態を確認します。

systemd-run

systemd-runは、あらかじめ.timer・.serviceユニットファイルを作成しておかなくても、コマンドラインから一時的な(トランジェントな)unitを作成してその場でコマンドを実行できるコマンドです。作成されたunitは、通常のサービスユニットと同様にsystemctlで状態を確認できます。

タイマーとして使う場合は、--on-calendar=・--on-active=・--on-boot=といったオプションを指定します。例えば、次のコマンドは5分後に指定したコマンドを1回だけ実行します。

systemd-run --on-active=5min /usr/local/bin/one-shot-task.sh

atが単発の実行予約に特化しているのに対し、systemd-runはより汎用的に「一時的なunitとしてコマンドを実行する」ためのコマンドであり、タイマーとしての機能はその応用の一つという位置づけです。


補足

  1. Vixie cron系列の実装によく見られる拡張で、標準の書式ではありません ↩
  2. 具体的な配置(/var/spool/cron/crontabs/のようにさらにサブディレクトリを持つか等)はディストリビューションによって異なります。 ↩
  3. crontabコマンドを経由しないと、権限設定やcronデーモンへの反映が正しく行われない場合があります ↩
  4. 対象となるファイル名の条件はrun-partsの実装によって異なります。 ↩
  5. 受け付けられる日時の書式の詳細は、atの実装(多くのディストリビューションではatパッケージ、内部的にatdデーモンが実行を担います)によって細部が異なる場合があります。 ↩
  6. anacronパッケージがインストールされていない場合や、ディストリビューションの構成によっては、/etc/crontab側が直接run-partsを呼び出す従来通りの構成になっていることもあります。「どの環境でも必ずanacron経由である」とは断定できません。 ↩