「crontab -e で設定したのに、なぜかジョブが動いていない。ログの見方もよくわからない」
こういった悩みを持つエンジニアは多いはずです。cronは歴史ある定番ツールですが、環境変数の引き継ぎや実行ログの管理が独特で、トラブルのたびに原因究明に手間がかかります。
この記事では、systemd timer を使ってcronジョブをモダンな方法で置き換える手順を解説します。.serviceファイルと.timerファイルの書き方から、systemctlによる管理・ログ確認まで、実際のサーバー環境で使える実践例を交えて丁寧に説明します。
この記事のポイント
・systemd timerは.serviceと.timerの2ファイルで定義する
・journalctlでジョブの実行ログをcronより簡単に追跡できる
・OnCalendar=で柔軟な時刻指定が可能(週次・月次も簡単)
・AccuracySec=で実行タイミングの精度をコントロールできる
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
systemd timerとは?cronとの違いを理解する
systemd timerとは、systemdの仕組みを使ってジョブを定期実行するための機能です。Linuxのinitシステムとして広く使われているsystemdには、サービス管理だけでなく、タイマー機能が標準で搭載されています。cronと比べたとき、systemd timerには次のような特徴があります。
| 比較項目 | cron | systemd timer |
|---|---|---|
| 設定ファイル | crontab(1ファイルに全定義) | .serviceと.timerの2ファイル |
| 実行ログ | /var/log/cron(環境による) | journalctlで統一管理 |
| 環境変数 | cronの最小環境変数のみ | Environmentや.envファイルで明示指定 |
| 依存関係 | 設定不可 | After=やWants=で制御可能 |
| ミス検出 | 実行時まで気づきにくい | systemctl statusでユニットの構文エラーを事前検出 |
| 実行ユーザー | crontabのユーザーに依存 | User=で明示指定できる |
特にjournalctlによるログ追跡は、cronの「なぜ動いていないかわからない」という問題を大幅に解消してくれます。
動作確認環境: RHEL 9.4 / Rocky Linux 9.3 / Ubuntu 24.04 LTS(systemd 252以降)
systemd timerの基本構成(.serviceと.timerの関係)
systemd timerを使う際は、必ず2つのユニットファイルをセットで作成します。・.serviceファイル: 実際に実行するコマンドやスクリプトを定義する
・.timerファイル: いつ.serviceを起動するかのスケジュールを定義する
ファイル名は同じベース名にすることがルールです。例えば `backup.service` と `backup.timer` のようにペアにします。
ユニットファイルの配置場所は用途によって2種類あります。
・/etc/systemd/system/: システムワイドなユニット(root権限が必要な処理)
・~/.config/systemd/user/: ユーザー単位のユニット(一般ユーザーでも作成可能)
本記事ではシステムワイドな設定(/etc/systemd/system/)を前提に解説します。
実践例:バックアップスクリプトをsystemd timerで毎日実行する
ここでは `/usr/local/bin/backup.sh` というバックアップスクリプトを、毎日午前2時に実行するsystemd timerを作成します。1. バックアップスクリプトの準備
まず、実行するスクリプトを用意します。# /usr/local/bin/backup.sh を作成 cat <<'EOF' > /usr/local/bin/backup.sh #!/bin/bash BACKUP_DIR=/var/backup DATE=$(date +%Y%m%d) tar -czf "${BACKUP_DIR}/home_${DATE}.tar.gz" /home echo "backup completed: ${DATE}" EOF chmod +x /usr/local/bin/backup.sh
2. .serviceファイルを作成する
次に、スクリプトを実行するためのサービスユニットを作成します。# /etc/systemd/system/backup.service を作成 cat <<'EOF' > /etc/systemd/system/backup.service [Unit] Description=Daily Backup Service After=network.target [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh User=root EOF
3. .timerファイルを作成する
スケジュールを定義するtimerユニットを作成します。# /etc/systemd/system/backup.timer を作成 cat <<'EOF' > /etc/systemd/system/backup.timer [Unit] Description=Run backup.service every day at 02:00 [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target EOF
・Persistent=true: サーバーが停止していた場合、次回起動時に「実行漏れ」を補完する
・WantedBy=timers.target: timerユニット共通の設定。システム起動時に自動有効化される
4. timerを有効化・起動する
作成したtimerを有効化して動かします。# systemdにユニットファイルを認識させる systemctl daemon-reload # timerを有効化(システム起動時に自動開始) systemctl enable backup.timer # timerを今すぐ起動 systemctl start backup.timer # timerの状態を確認 systemctl status backup.timer
# systemctl status backup.timer の出力例 * backup.timer - Run backup.service every day at 02:00 Loaded: loaded (/etc/systemd/system/backup.timer; enabled; preset: disabled) Active: active (waiting) since Wed 2026-05-20 10:15:32 JST; 3min ago Trigger: Thu 2026-05-21 02:00:00 JST; 15h 44min left Triggers: * backup.service
OnCalendarの書き方|スケジュール指定パターン集
OnCalendarの書式は `曜日 年-月-日 時:分:秒` の形式です。アスタリスク(*)はワイルドカードとして使えます。| やりたいこと | OnCalendarの指定 |
|---|---|
| 毎日2時に実行 | OnCalendar=*-*-* 02:00:00 |
| 毎時0分に実行 | OnCalendar=*-*-* *:00:00 |
| 毎週月曜日の3時に実行 | OnCalendar=Mon *-*-* 03:00:00 |
| 毎月1日の6時に実行 | OnCalendar=*-*-01 06:00:00 |
| 30分ごとに実行 | OnCalendar=*-*-* *:00,30:00 |
| 平日の9時に実行 | OnCalendar=Mon..Fri *-*-* 09:00:00 |
| 年に一度(元日の0時) | OnCalendar=*-01-01 00:00:00 |
OnCalendar=の指定が正しいか事前に確認するには `systemd-analyze calendar` コマンドが便利です。
# スケジュール指定を検証する systemd-analyze calendar "Mon *-*-* 03:00:00" # 出力例 Original form: Mon *-*-* 03:00:00 Normalized form: Mon *-*-* 03:00:00 Next elapse: Mon 2026-05-25 03:00:00 JST (in UTC): Mon 2026-05-24 18:00:00 UTC From now: 4 days 16h 44min left
AccuracySec=でタイミング精度を制御する
systemd timerにはデフォルトで `AccuracySec=1min`(1分の精度誤差)が設定されています。これはシステムへの負荷分散のために意図的に設けられた「ゆらぎ」です。・AccuracySec=1s: 秒単位の精度が必要な場合(ただしCPUウェイクアップ頻度が増える)
・AccuracySec=1min: デフォルト。バックアップや定期レポートなら十分
・AccuracySec=1h: 精度をさらに下げてシステム負荷を最小化したい場合
バックアップやログ集計など、数分のズレが許容できるジョブであればデフォルトのまま使って問題ありません。
よく使うsystemctl管理コマンド
systemd timerを運用する際によく使うコマンドをまとめます。| やりたいこと | コマンド |
|---|---|
| ユニット変更を反映 | systemctl daemon-reload |
| timerを有効化 | systemctl enable backup.timer |
| timerを起動 | systemctl start backup.timer |
| timerの状態確認 | systemctl status backup.timer |
| 今すぐserviceを手動実行 | systemctl start backup.service |
| 全timerの一覧表示 | systemctl list-timers |
| timerを停止・無効化 | systemctl disable --now backup.timer |
`systemctl list-timers` は特に便利で、有効化されているすべてのtimerの次回実行予定を一覧表示します。
# 全timerの一覧を確認 systemctl list-timers --all # 出力例(抜粋) NEXT LEFT LAST PASSED UNIT ACTIVATES Thu 2026-05-21 02:00:00 JST 15h 44min Wed 2026-05-20 02:00:05 JST 8h ago backup.timer backup.service Thu 2026-05-21 00:00:00 JST 13h 44min Wed 2026-05-20 00:00:03 JST 10h ago logrotate.timer logrotate.service
journalctlでジョブの実行ログを確認する
systemd timerの最大の利点のひとつが、journalctlによるログ管理です。cronでは `/var/log/cron` を読むか、スクリプト内でログを書くかしかありませんでしたが、systemd timerはすべての実行ログがjournalに自動記録されます。# backup.serviceの実行ログを確認 journalctl -u backup.service # 直近10件のみ表示 journalctl -u backup.service -n 10 # リアルタイムでログを追う journalctl -u backup.service -f # 今日の実行ログだけ確認 journalctl -u backup.service --since today
May 20 02:00:05 web01.example.com systemd[1]: Starting Daily Backup Service... May 20 02:00:07 web01.example.com backup.sh[12345]: backup completed: 20260520 May 20 02:00:07 web01.example.com systemd[1]: backup.service: Deactivated successfully. May 20 02:00:07 web01.example.com systemd[1]: Finished Daily Backup Service.
トラブルシュート|よくあるエラーと対処法
1. timerが起動しない(Activeがinactiveのまま)
systemctl start後もActiveが `inactive` の場合は、まずステータスを確認します。systemctl status backup.timer journalctl -xe -u backup.timer
2. serviceは起動するがスクリプトが失敗する
cronとは異なり、systemd serviceの実行環境はPATHが最小限です。スクリプト内でフルパスを使うか、Environmentでパスを明示します。# .serviceファイルにEnvironmentを追加する例 [Service] Type=oneshot ExecStart=/usr/local/bin/backup.sh Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin User=root
3. Persistent=trueなのに実行漏れが補完されない
Persistent=trueは「前回の実行がトリガー時刻を過ぎていた場合に補完する」機能です。timerが有効化(enabled)されていることが前提です。`systemctl is-enabled backup.timer` でenabledと表示されるか確認します。4. ユニットファイル変更後に反映されない
.serviceや.timerファイルを編集した後は必ず `systemctl daemon-reload` を実行します。これを忘れると古いファイルのまま動作し続けます。# ファイル編集後は必ずこのセットを実行する systemctl daemon-reload systemctl restart backup.timer systemctl status backup.timer
cronとsystemd timerの使い分けの考え方
systemd timerが優れているからといって、cronを完全に廃止する必要はありません。現場での使い分けの目安を整理します。・systemd timerが向いているケース
複数のサービスに依存するジョブ(After=で依存関係を制御したい)
実行結果をjournalctlで一元管理したいケース
サーバー停止中の実行漏れをPersistent=trueで補完したいケース
・cronが向いているケース
既存のcrontabエントリを移行するコストが高い環境
Dockerコンテナ内など、systemdが動作しない環境
ユーザー単位の設定を`crontab -e`で素早く追加したい場合
新規にジョブを追加するなら、systemd timerを選ぶのが今のLinuxサーバー運用のスタンダードになりつつあります。
本記事のまとめ
| やりたいこと | コマンド・設定 |
|---|---|
| ユニット変更を反映 | systemctl daemon-reload |
| timerを有効化・起動 | systemctl enable --now backup.timer |
| スケジュール指定の検証 | systemd-analyze calendar "OnCalendar指定文字列" |
| 全timerの次回実行確認 | systemctl list-timers --all |
| 実行ログの確認 | journalctl -u backup.service -n 20 |
| 今すぐ手動実行 | systemctl start backup.service |
| timerを停止・無効化 | systemctl disable --now backup.timer |
systemd timerは、cronに比べてログ追跡・エラー検出・依存関係管理の面で大きなアドバンテージがあります。.serviceと.timerの2ファイルを用意するだけで使い始められますので、新規のジョブ追加時にはぜひ活用してみてください。
Linuxのサービス管理についてさらに詳しく学びたい場合は、以下の関連記事も参考にしてください。
・systemd-analyze で起動時間計測
・Linux ポート確認の全コマンド
・Linux DNS 設定の基本
systemd timerを含めた、安定したサーバー運用の基礎を固めませんか?
systemd timerの活用はサーバー自動化の一歩ですが、サービス管理・ログ監視・セキュリティ設定と合わせて体系的に身につけることで、現場で頼られる存在になれます。
ネットの切れ端の情報をコピペするだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
登録10秒/合わなければ解除3秒 / 詳細はこちら
- 前のページへ:basenameとdirnameコマンドでパスからファイル名・ディレクトリ名を取得する方法|シェルスクリプト実践活用も
- この記事の属するカテゴリ:Linuxtips・システム管理へ戻る

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は1分、解除もいつでも可。
登録無料・いつでも解除できます