LinuxにおけるSystemdタイマーの活用:現代のCronを置き換える必要不可欠なツール

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

コンテキストとSystemdタイマーについて話す理由

もしあなたが長期間Linuxサーバーを管理しているなら、おそらくcronには非常に慣れていることでしょう。何十年もの間、日次バックアップから時間ごとのログローテーションまで、あらゆるスケジューリング作業を信頼して任せられるツールでした。そして、たいていは問題なく動作していましたよね?

まあ、ほとんどは。cronが確かに有能である一方で、いくつか厄介な問題点もあります。DevOpsエンジニアやシステム管理者にとっては、これらが物事を非常に複雑にする可能性があります。

私自身、シェルとcronの実行環境との間で環境変数の違いがあったために、サイレントに失敗したcronジョブのデバッグに何時間も費やしたことがあります。これらの問題を修正するには、スクリプト自体に詳細なログを追加するか、cronの限られたコンテキストを再現するためにコマンドを手動で実行する必要があることがよくあります。さらに、組み込みの依存関係管理もありません。重要なサービスが実行されていない場合、スクリプトにそのロジックを手動で組み込まない限り、cronジョブは、正常な再試行や通知なしに失敗する可能性があります。

まさにこの点で、Systemdタイマーは非常に貴重な存在となります。これらは、現代のLinuxディストリビューションにおいてcronに代わるネイティブで強力かつ深く統合されたソリューションを提供します。あなたのシステムがsystemdを使用している場合(Ubuntu、Fedora、CentOS/RHEL 7+のような最近のほとんどのディストリビューションがそうであるように)、すでに洗練されたタスクスケジューラーが利用可能です。これはシステムのサービスやロギングとシームレスに統合されます。

では、なぜ切り替えるのでしょうか?私にとって、その利点は明白です。Systemdタイマーはjournalctlを介して一貫した詳細なロギングを提供し、何が、いつ、どのような出力で発生したかを正確に確認できます。

また、システムの依存関係も考慮するため、特定のサービスが完全に稼働した後のみにタスクを実行するように設定できます。それに加えて、標準のsystemctlコマンドを使用して管理およびトラブルシューティングがはるかに簡単です。私の経験では、4GB RAMを搭載した本番のUbuntu 22.04サーバーで、このアプローチは、従来のcronセットアップと比較して、より厳密なシステム統合と予測可能な実行環境のおかげで、リソースを大量に消費する自動化スクリプトの処理時間を大幅に短縮しました。

インストール(というより確認)

良いニュースです。もしあなたが最新のLinuxディストリビューションを使用しているなら、systemdはほぼ間違いなくすでにインストールされ、実行されています。つまり、Systemdタイマーはすぐに利用可能です。別途パッケージをインストールする必要はありません。これはcronの場合(多くの場合cronievixie-cronが必要)とは異なります。

systemdがあなたのinitシステムであり、正しく動作していることを確認するには、以下のコマンドを使用します:

systemctl --version

以下のような出力が表示され、実行中のsystemdのバージョンが示されるはずです:

systemd 249 (249.11-0ubuntu3.11)
+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 +JPKG +LZ4 +ZSTD +SECCOMP +PWQUALITY +P11KIT +KERNEL_USERSPACE_HEADERS +XKBCOMMON +NSSUSELINUX +RESOLVCONF +BPF_FRAMEWORK +GLIB2

この出力は、systemdが確かに存在し、システムのサービスとタイマーを管理する準備ができていることを確認します。

設定:最初のSystemdタイマーを作成する

Systemdタイマーを使用してタスクをスケジュールするには、通常、2つの異なるユニットファイルが必要です。まず、サービスユニット.service)が実行するアクションを定義します。次に、タイマーユニット.timer)がそのアクションをいつ、どのくらいの頻度でトリガーするかを指定します。.serviceファイルを実行可能スクリプト、.timerファイルをそれに対応するcrontabエントリと考えることができます。

サービスユニットの作成

まず、自動化したいタスクを定義しましょう。このウォークスルーでは、メッセージをログに記録し、バックアップ操作をシミュレートする簡単なスクリプトを作成します。このスクリプトは、標準的でアクセスしやすい場所である/usr/local/bin/に配置します。

my-backup.shというファイルを作成します:

#!/bin/bash

LOGFILE="/var/log/my-backup.log"
TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")

echo "[$TIMESTAMP] 日次バックアップを開始しています..." >> $LOGFILE

# バックアップ操作をシミュレート
sleep 5

echo "[$TIMESTAMP] 日次バックアップが正常に完了しました!" >> $LOGFILE

exit 0

実行可能にします:

sudo chmod +x /usr/local/bin/my-backup.sh

次に、サービスユニットファイル自体を作成します。このファイルは、systemdにスクリプトを正確に実行する方法を指示します。これは、カスタムユニットファイルの従来のディレクトリである/etc/systemd/system/に保存します。

/etc/systemd/system/my-backup.serviceを作成します:

[Unit]
Description=私の日次バックアップサービス

[Service]
Type=oneshot
ExecStart=/usr/local/bin/my-backup.sh
WorkingDirectory=/tmp
User=root
Group=root

[Install]
WantedBy=timers.target
  • [Unit]: このセクションには一般的な情報が保持されます。Descriptionフィールドは、サービスの目的を特定するのに特に役立ちます。
  • [Service]: これはサービスの主要な側面を定義します。
    • Type=oneshot: これはsystemdに、コマンドが一度実行されてから終了することを伝えます。systemdはその完了を待ちます。
    • ExecStart: 実行するコマンドまたはスクリプトを指定します。
    • WorkingDirectory: コマンドが実行されるディレクトリを設定します。
    • User/Group: スクリプトが実行されるユーザーとグループのパーミッションを定義します。これは正しいパーミッションと環境コンテキストのために不可欠です。
  • [Install]: インストール関連のディレクティブが含まれます。WantedBy=timers.targetは、このサービスがタイマーによってトリガーされるように設計されていることを示します。

タイマーユニットの作成

次に、サービスをアクティブにする役割を担うタイマーユニットを定義します。サービスファイルと同様に、これも/etc/systemd/system/に配置され、サービスと同じ基本名を持ち、.timer拡張子が付いている必要があります。

/etc/systemd/system/my-backup.timerを作成します:

[Unit]
Description=日次バックアップタイマーを実行

[Timer]
OnCalendar=daily
Persistent=true
Unit=my-backup.service

[Install]
WantedBy=timers.target
  • [Unit]: サービスユニットと同様に、このセクションは記述的な名前のためです。
  • [Timer]: ここでタイミングパラメータを設定します。
    • OnCalendar=daily: この重要な設定はスケジュールを指定します。dailyは単純ですが、systemdは非常に柔軟な表現を提供します:
      • hourly: 毎時間実行します。
      • *-*-* 03:00:00: 毎日午前3時ちょうどに実行します。
      • Mon,Fri *-*-* 18:00:00: 毎週月曜日と金曜日の午後6時にトリガーします。
      • minutely: 毎分実行します(リソースを大量に消費するタスクでは細心の注意を払って使用してください!)。
      • OnUnitActiveSec=5min: 関連サービスが最後にアクティブになってから5分後に実行します。
      • OnBootSec=10min: システム起動から10分後に実行します。
    • Persistent=true: 強力な機能です。スケジュールされた実行が予定されていたときにsystemdがオフラインであった場合、ジョブはシステム起動時に直ちに実行されます。これは従来のcronジョブのanacronの動作を模倣しています。
    • Unit=my-backup.service: このディレクティブは、スケジュールが満たされたときにどのサービスユニットをアクティブにするかをタイマーに正確に伝えます。
  • [Install]: ここでのWantedBy=timers.targetは、タイマーがシステムのタイマー管理フレームワークに適切に統合されることを保証します。

タイマーの有効化と開始

ユニットファイルを作成または変更したら、systemdデーモンをリロードすることが不可欠です。これにより、すべての新しい変更が反映されます:

sudo systemctl daemon-reload

デーモンがリロードされたら、タイマーを有効にして開始できます。有効にするとシステム起動時に自動的にアクティブになり、開始すると現在のセッションで直ちにアクティブになります。

sudo systemctl enable my-backup.timer
sudo systemctl start my-backup.timer

.serviceユニットを直接有効にしたり開始したりするのではなく、.timerユニットを有効にして開始していることに注意することが重要です。タイマーはトリガーとして機能し、サービスがいつ実行されるかを調整します。

検証と監視

Systemdタイマーの最も魅力的な利点の1つは、その実行を検証および監視することがいかに簡単かということです。

タイマーのステータスを確認する

システム全体のアクティブなタイマーを検査し、新しく作成したタイマーのステータスを具体的に確認するには、list-timersコマンドを使用します:

systemctl list-timers

以下のような出力が得られます:

NEXT                          LEFT          LAST                          PASSED       UNIT                         ACTIVATES
Thu 2026-03-20 00:00:00 UTC   10h left      Wed 2026-03-19 00:00:00 UTC   14h ago      my-backup.timer              my-backup.service

2 timers listed.

この出力は、タイマーが次にいつ実行される予定か(NEXTの下)と、その最後の実行時刻(LAST)を明確に示しています。特定のタイマーに関するさらに詳細な情報を得るには、以下を使用できます:

systemctl status my-backup.timer

出力は、それがアクティブで有効になっていることを確認します:

● my-backup.timer - 日次バックアップタイマーを実行
     Loaded: loaded (/etc/systemd/system/my-backup.timer; enabled; vendor preset: enabled)
     Active: active (waiting) since Wed 2026-03-19 14:00:00 UTC; 14h ago
    Trigger: Thu 2026-03-20 00:00:00 UTC; 10h left
   Triggers: ● my-backup.service
   Docs: man:systemd.timer(5)

サービスステータスとログの確認

タイマーがトリガーされると、関連するサービスユニットが起動します。サービスが正常に実行されたことを確認し、その出力を確認するには、サービスユニットのステータスとそのジャーナルログを検査する必要があります。

systemctl status my-backup.service

これにより、最後の実行ステータスが表示されます:

● my-backup.service - 私の日次バックアップサービス
     Loaded: loaded (/etc/systemd/system/my-backup.service; static)
     Active: inactive (dead) since Wed 2026-03-19 00:00:05 UTC; 14h ago
   Main PID: 12345 (code=exited, status=0/SUCCESS)
        CPU: 50ms

スクリプトが標準出力または標準エラーに出力した内容を含む詳細な出力を得るには、journalctlは非常に強力なツールです:

journalctl -u my-backup.service --since "1 day ago"

このコマンドは、my-backup.serviceからのエントリのみを1日前までさかのぼってシステムジャーナルをフィルタリングします。サンプルスクリプトからのechoメッセージがここに表示され、その正常な実行が確認されます。この一元化されたロギング機能は、散在するログファイルをふるいにかけたり、個々のcronスクリプトごとにロギングを手動で設定したりするよりも大きな利点を提供します。

トラブルシューティングのヒント

  • パーミッション: スクリプトに実行パーミッション(chmod +x)があることを常に確認してください。また、サービスユニットで指定されたUserが、スクリプトがやり取りするファイルまたはディレクトリに対して適切なパーミッションを持っていることを確認してください。
  • パス: スクリプトとそのサービスユニット内でアクセスするすべてのファイルに対して、常に絶対パスを使用してください。systemdサービスの実行環境は非常に最小限である可能性があることを忘れないでください。
  • リロード: 変更後、sudo systemctl daemon-reloadの実行を忘れていませんか?もしそうなら、更新は反映されません。これは非常によくある見落としです!
  • タイムゾーン: デフォルトでは、OnCalendarの式はシステムのローカルタイムゾーンに依存します。特にマルチサーバー環境や地理的に分散した環境では、この点に留意してください。
  • 停止/無効化: タイマーが期待どおりに動作しない場合、または一時的に一時停止する必要がある場合は、これらのコマンドを使用できます:
    sudo systemctl stop my-backup.timer
    sudo systemctl disable my-backup.timer

    stopコマンドは現在の活動を停止し、disableは以降の起動時にタイマーが自動的に開始されるのを防ぎます。

cronからSystemdタイマーへの移行は、最初は大きな変更のように感じられるかもしれませんが、その利点はすぐに明らかになります。systemdエコシステムに統合することで、強化された制御、優れたデバッグ機能、そしてLinuxシステムの残りの部分とのシームレスな統合が得られます。これは、今日のサーバー管理の要求に完全に適合した、真に現代的なタスクスケジューリングのアプローチです。

Share: