「昨日から夜間バッチが動いていないようです」。

こうした連絡が入るのは、たいてい朝一番です。日次処理、請求処理、データ連携、バックアップなど、cron で動いている処理は普段は意識されません。しかし、止まったときの影響は小さくありません。

cron ジョブが動いていないように見える場合でも、実際には「実行されていない」「実行されたが失敗した」「実行されたが期待した結果になっていない」のどれかに分かれます。この記事では、現場で最初に確認する調査の流れをまとめます。

まず確認する:cron は実行されたか

最初に見るべきなのは、対象のコマンドが cron から呼び出された記録があるかどうかです。ここを確認せずにスクリプトを直し始めると、原因の切り分けが遠回りになります。

ログで実行の有無を確認する

cron の実行履歴はシステムログに記録されます。場所は OS によって異なります。

# Debian / Ubuntu 系
grep CRON /var/log/syslog | tail -30

# RHEL / CentOS 系
grep CRON /var/log/cron | tail -30

# systemd を使っているシステム
journalctl -u cron -u crond --since "yesterday"

ここで実行された記録が ない 場合は、cron デーモン自体が止まっている、対象ユーザーの crontab が読まれていない、またはスケジュールの書き方が想定と違っている可能性があります。

記録は ある のに処理が完了していない場合は、cron からコマンドは呼び出されています。その場合は、スクリプトのエラー、実行ユーザーの権限、環境変数、パス指定などを確認します。

cron デーモンの状態を確認する

systemctl status cron    # Debian / Ubuntu 系
systemctl status crond   # RHEL / CentOS 系

inactivefailed になっていれば、まず cron を起動してください。

systemctl start cron    # Debian / Ubuntu 系
systemctl start crond   # RHEL / CentOS 系

再発を防ぐには、自動起動が有効になっているかも確認します。

systemctl is-enabled cron
systemctl is-enabled crond

crontab の設定を確認する

設定内容を確認する

crontab -l             # 現在のユーザーの crontab
crontab -l -u www-data # 別ユーザーの crontab(root で実行)
cat /etc/cron.d/*      # システム全体の cron 設定

スケジュールの書き方を確認する

crontab の書式は 分 時 日 月 曜日 コマンド の順です。

# 毎日 2:30 に実行する例
30 2 * * * /opt/scripts/batch.sh

よくあるミス:

  • 分と時を逆に書いている
  • # のコメント行になっている(意図せず無効化されている)
  • 最終行に改行がない(一部の実装では最終行が実行されない)
  • /etc/cron.d/ 配下のファイルで、実行ユーザーの列を書き忘れている

/etc/cron.d/ 配下のファイルは、ユーザーごとの crontab -e とは書式が異なります。時刻指定の後に、どのユーザーで実行するかを書く必要があります。

# /etc/cron.d/my-batch の例
30 2 * * * www-data /opt/scripts/batch.sh

環境変数の問題

cron は、ログインシェルで実行したときと同じ環境変数を持っていません。手動で実行すると動くのに cron では動かない場合、PATH やアプリケーション用の環境変数が不足していることがよくあります。

コマンド内で使うパスを絶対パスで指定するか、crontab の先頭で PATH を定義します。

PATH=/usr/local/bin:/usr/bin:/bin
30 2 * * * /opt/scripts/batch.sh

スクリプト自体を確認する

実行権限があるか

ls -l /opt/scripts/batch.sh

-rwxr-xr-x のように実行権限(x)がなければ動きません。

chmod +x /opt/scripts/batch.sh

ただし、権限を広げすぎるのは避けます。実行ユーザーが決まっている場合は、そのユーザーで読めて実行できる権限になっているかを確認します。

スクリプト内のパスが絶対パスになっているか

cron 実行時のカレントディレクトリは、ユーザーのホームディレクトリになることが多いです。/etc/cron.d/ やサービスの構成によって前提が変わることもあるため、スクリプト内では相対パスに頼らない方が安全です。

たとえば、次のような処理は cron では失敗することがあります。

php artisan schedule:run

この場合は、対象ディレクトリへ移動してから実行するか、絶対パスで指定します。

* * * * * cd /var/www/example && /usr/bin/php artisan schedule:run

エラー出力をログに残す

デフォルトの動作と MAILTO

cron の標準出力・標準エラー出力は、メール配送が設定されている環境では実行ユーザー宛てに送られます。MAILTO を設定すると宛先を変更できます。

MAILTO=admin@example.com
30 2 * * * /opt/scripts/batch.sh

MAILTO でメールが届いていれば、標準出力や標準エラー出力の内容を確認できます。

一方で、通常のシステムログ(/var/log/syslog/var/log/cron)にコマンドの出力内容までは記録されません。システムログに残るのは、「いつ・誰が・何を実行したか」という実行の事実です。

Jun 23 02:30:01 hostname CRON[12345]: (user) CMD (/opt/scripts/batch.sh)

そのため、システムログだけを見てもエラーの詳細まではわかりません。

ファイルへのリダイレクト

ここまで見たように、cron のシステムログに残るのは実行の事実だけです。メール配送が設定されていない環境では、標準出力や標準エラー出力を確認できないことがあります。

そのため、調査しやすくするには、出力をファイルにリダイレクトして残しておくのが有効です。

30 2 * * * /opt/scripts/batch.sh >> /var/log/batch.log 2>&1

リダイレクトを設定すると、標準出力・標準エラー出力はファイルに書き込まれます。この場合、cron から見るとメール送信用の出力がなくなるため、通常は MAILTO へのメール送信は行われません。システムログには、引き続き実行の事実のみが記録されます。

MAILTO とファイル記録を両立する(tee)

tee -a を使うと、MAILTO へのメール送信とファイルへの追記を同時に行えます。

30 2 * * * /opt/scripts/batch.sh 2>&1 | tee -a /var/log/batch.log

tee は受け取った出力をファイルに書きつつ、自分の標準出力にも流します。cron はパイプライン全体の出力を MAILTO 用に受け取るため、メールも届きます。-a は追記モードの指定で、実行のたびにファイルが上書きされるのを防ぎます。

注意:終了コードは tee のものになる

パイプを使うと、パイプライン全体の終了コードは最後のコマンド(tee)のものになります。スクリプトが失敗しても tee が成功すれば終了コード 0 として扱われます。終了コードを正確に拾いたい場合は bash -o pipefail を使います。

30 2 * * * /bin/bash -o pipefail -c '/opt/scripts/batch.sh 2>&1 | tee -a /var/log/batch.log'

systemd timer を使っている場合

最近の Linux では、cron の代わりに systemd timer で定期実行していることがあります。特にパッケージで導入された定期処理は、cron ではなく timer と service の組み合わせになっている場合があります。

# 登録されているタイマー一覧と次回実行時刻を確認
systemctl list-timers

# 特定のタイマーの状態を確認
systemctl status my-batch.timer

# 実行ログを確認
journalctl -u my-batch.service --since "yesterday"

おわりに

cron の問題は、「実行されていない」「実行されたが失敗している」「実行されたが期待した結果になっていない」の3パターンに分けると調査しやすくなります。

実行履歴がなければ cron 側の設定やデーモンを確認します。実行履歴がある場合は、スクリプトの権限、環境変数、パス、出力ログを確認します。エラーログが残っていない環境では、まずリダイレクトの設定を入れて、次に失敗したときの手がかりを残せるようにしておくことが重要です。

調査の結果として修正範囲が広い場合や、原因が特定できない場合は障害調査・原因分析またはレガシーシステム保守からご相談ください。

smiyabe

宮部 敏史

20歳からプロとして現場に立ち続けるシステムエンジニア。Webシステム開発・サーバ運用を中心に、現場目線での技術発信を行っています。ヘヴィメタル系ボーカリスト・ベーシストでもあり、現在は「ななこぴ⚡️」で活動中。料理と食べることも好きです。

← ブログ一覧へ戻る

システムの「困った」、まずはお聞かせください

原因不明の障害、誰も触れない古いシステム、属人化した運用。状況の整理からお手伝いします。お見積り・ご相談は無料です。

お問い合わせ