cronが動かない原因と対処法 - crontabの使い方とログ確認
この記事でできるようになること
- cron が動かない原因を順序立てて切り分けられる
- crontab の時刻指定を読み書きできる
- PATH・権限・相対パスの定番の罠を回避できる
前提知識(先に読むと理解しやすい記事)
この記事で解決できること
- cron が「動かない」「実行されない」原因を体系的に切り分けられます。
- ログの場所と確認方法が分かります。
- crontab の時刻指定を読み書きできます。
- 実務で頻発する「ユーザー・PATH・権限」の罠を避けられます。
結論(障害対応の型)
cron が動かないときは、感覚で直さない。必ず次の順で見る。
- 本当に登録されているか
- どのユーザーの cron か
- ログに実行痕跡があるか
- 手動実行すると動くか
- PATH / 権限 / 実行ファイル問題
前提(対象環境)
- OS:Ubuntu
- 新人〜実務初期
- root / 一般ユーザー両方を想定
先に 1 つだけ警告:crontab -r は使わない
crontab -r は、そのユーザーの登録内容を確認なしで全部消すコマンドです。
crontab -e(編集)とキーが隣接しているため、押し間違いによる全消しが定番の事故になっています。
削除した内容を戻す機能はありません。
- 編集の前に必ず控えを取る:
crontab -l > ~/crontab-$(date +%Y%m%d).bak - 一部だけ止めたいなら
crontab -eで該当行の先頭に#を付ける - どうしても削除する場合は
crontab -i -rを使う(-iは削除前に確認を出す)
1. cron の種類(ここを誤解すると詰む)
結論: ユーザーcron・root cron・
/etc/cron.*があり、実行ユーザーが異なる。まずどこに書いたか明確にする。
Ubuntu には cron が複数あります。
先に用語を整理します。
| 用語 | 一行の意味 | 混同されやすい言い方 |
|---|---|---|
| デーモン | 画面を持たず、裏で動き続けるプログラム | 「常駐プロセス」「サービス」とも呼ばれます |
| cron | 決めた時刻にコマンドを自動実行するデーモン | 「cron デーモン」「crond」も同じものです |
| crontab | 実行予定を書いた設定ファイル、およびそれを編集するコマンド | 「クーロンタブ」と読みます |
| ジョブ | crontab に書いた 1 行分の実行予定 | 「エントリ」「タスク」も同義です |
| MTA | メールを送る役割のソフトウェア | Postfix / sendmail などが該当します |
1-1. ユーザー cron
$ crontab -e
- 実行ユーザー:そのユーザー
- 一番よく使う
1-2. root cron
$ sudo crontab -e
- 実行ユーザー:root
- 権限が必要な処理用
1-3. /etc/crontab と /etc/cron.d
システム全体用の定義です。書式が 6 フィールドで、5 つの時刻指定の次に実行ユーザー欄が入ります。
# 分 時 日 月 曜日 ユーザー コマンド
0 3 * * * root /usr/local/bin/backup.sh
ユーザー cron と同じ 5 フィールドで書くと、コマンド名がユーザー名として読まれます。
ログに unknown user などが出て動きません。書く場所によって書式が変わる点に注意してください。
1-4. /etc/cron.daily などのディレクトリ
/etc/cron.hourly / /etc/cron.daily などに置いたスクリプトは run-parts が実行します。制約が 2 つあります。
- 実行権限が必要(
chmod +x) - ファイル名にドットを含むと無視される(
backup.shは実行されない。拡張子を外してbackupにする)
どこに書いたかをまず明確にする
2. crontab の書き方(時刻指定の 5 フィールド)
結論: 時刻指定は分・時・日・月・曜日の 5 フィールドで、左から順に細かい単位が並ぶ。
ユーザー crontab(crontab -e で開くもの)の 1 行は、「いつ実行するか」5 つと「何を実行するか」で構成されます。
/etc/crontab / /etc/cron.d は §1-3 のとおり 6 フィールドなので混同しないでください。
* * * * * コマンド | | | | | | | | | +-- 曜日(0-7、0 と 7 は日曜) | | | +---- 月(1-12) | | +------ 日(1-31) | +-------- 時(0-23) +---------- 分(0-59)
* は「毎回」という意味です。
例:
0 3 * * *— 毎日 3:00*/5 * * * *— 5 分おき0 0 * * 0— 毎週日曜の 0:00
「日」と「曜日」の両方を * 以外にすると、どちらか一方でも一致すれば実行されます。
0 3 1 * 1 は「毎月 1 日」と「毎週月曜」の両方で動きます。片方だけにしたい場合、もう一方は * にしてください。
crontab のコマンド部では、エスケープしていない % が改行に置き換えられます。
date +%Y%m%d のような書き方は、シェルでは動いても crontab に貼った瞬間に壊れます。
# NG(% 以降が切れる)
0 3 * * * /home/user/backup.sh >> /home/user/log/backup-$(date +%Y%m%d).log 2>&1
# OK(\% とエスケープする)
0 3 * * * /home/user/backup.sh >> /home/user/log/backup-$(date +\%Y\%m\%d).log 2>&1
日付処理をスクリプト側に寄せてしまうのも確実な回避策です。
2-1. 書いた内容が意図どおりか先に確かめる
いきなり本番の処理を登録せず、まず 1 分おきに date を書き出すだけの行で動作を確認すると安全です。
* * * * * /usr/bin/date >> /tmp/cron-test.log 2>&1
数分待って /tmp/cron-test.log に行が増えていれば、cron 自体は動いています。
確認が済んだらこの行は消してください。ログファイルが増え続けます。
3. 登録されているか確認
結論:
crontab -lとsudo crontab -lで登録内容を確認する。「登録したつもり」が最多の事故原因。
$ crontab -l $ sudo crontab -l
crontab -l は登録内容を表示するだけで、何も変更しません。安全に何度でも実行できます。
「登録したつもり」が一番多い事故。
4. cron のログを見る(最重要)
結論:
grep CRON /var/log/syslogかjournalctl -u cronで実行痕跡を確認。ログに出ない=実行されていない。
4-1. syslog から確認
$ grep CRON /var/log/syslog
Dec 15 03:00:01 web01 CRON[2451]: (user) CMD (/home/user/backup.sh) Dec 15 03:05:01 web01 CRON[2478]: (root) CMD (/usr/local/bin/cleanup.sh)
(user) の部分が実行ユーザー、CMD (...) が実行されたコマンドです。
時間を絞る:
$ grep CRON /var/log/syslog | tail -n 50
4-2. journalctl で確認
$ journalctl -u cron
直近だけ:
$ journalctl -u cron -n 100
ログに出ていない=実行されていない
/var/log/syslog が存在しない構成では journalctl -u cron を使います。
どちらのコマンドもログを表示するだけで、cron の設定は変わりません。
5. 「実行されているが失敗している」ケース
結論: ログに
CMDが出ていればcron自体は動いている。実行ユーザーで手動実行して原因を切り分ける。
ログに次が出ることがある。
CMD (/path/to/script.sh)
これは cron自体は動いている。
次にやること:
$ sudo -u <cron_user> /path/to/script.sh
手動実行は、そのスクリプトが行う処理を実際に実行します。 ファイル削除やデータ更新を含むスクリプトの場合、テスト用のディレクトリで試すか、処理内容を先に読んでから実行してください。
6. 一番多い罠①:PATHが違う
結論: cronのPATHは極端に短い。コマンドはフルパスで書くか、冒頭でPATHを定義して回避する。
cron の PATH は極端に短い。 PATH とは、コマンド名だけで実行できる場所の一覧です。ログイン時のシェルと cron では中身が違います。
NG例
mysqldump ...
OK例
/usr/bin/mysqldump ...
フルパスは which で調べられます。
$ which mysqldump /usr/bin/mysqldump
対策:
- フルパスで書く
- 冒頭で PATH を定義
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
7. 一番多い罠②:実行権限がない
結論:
Permission deniedが出たら実行権限不足。ls -lで確認しchmod +xで付与する。
Permission denied
確認:
$ ls -l script.sh
対処:
$ chmod +x script.sh
chmod +x は誰に付けるかを省略した書き方で、通常は所有者・グループ・その他へまとめて実行権限が付きます。
自分だけに付けたい場合は chmod u+x script.sh と対象を明示してください。
8. 一番多い罠③:相対パス
結論: cronは実行ディレクトリが不定。
./script.shは避け、必ず絶対パスで指定する。
cron は どこで実行されるか分からない。
NG
./script.sh
OK
/home/user/script.sh
スクリプトの中で相対パスを使っている場合も同じ理由で失敗します。スクリプト内のファイル指定も絶対パスにしてください。
9. メール通知(失敗を可視化)
結論:
MAILTOで失敗を通知できる。メールが来ない場合はMTA未設定かcron自体が動いていない。
cron はジョブが何か出力を出したとき、その内容をメールで送る。 エラーメッセージも出力の一種なので、失敗の検知に使える。
MAILTO=you@example.com
メールが来ない場合:
- MTA未設定
- そもそも cron が動いていない
メールに頼れない環境では、実行結果をファイルへ書き出す方が確実です。
0 3 * * * /home/user/backup.sh >> /home/user/log/backup.log 2>&1
>> は追記、2>&1 はエラー出力も同じファイルへまとめる指定です。
出力先は実行ユーザーが書き込めるパスにしてください。
一般ユーザーの cron から /var/log/ へ書こうとすると Permission denied になり、リダイレクトごと失敗します。
/var/log/ 配下へ書くのは、root cron の場合か、あらかじめ書き込み権限を付与した専用ファイルがある場合に限ります。
10. cron が「重い処理」の犯人になるケース
結論: バックアップやrsync等の重い処理がI/O・CPU負荷の犯人になりやすい。負荷調査記事と併せて確認する。
- バックアップ
- ログ圧縮
- rsync
- Docker cleanup
負荷が跳ねた時刻と、これらのジョブが動く時刻が一致していないかを確認する。
突き合わせには journalctl -u cron --since "<時刻>" で実行痕跡を見るのが早い。
やってはいけないこと
- ログを見ずに書き換える
- root cron に何でも入れる
- フルパスを書かない
- 手動実行テストを省略する
- 控えを取らずに
crontab -rを実行する
11. 作業完了チェックリスト
結論: 登録・実行痕跡・出力先・控えの 4 点が揃っていれば、cron の設定作業は完了と判断できる。
- [ ]
crontab -lに意図した行が入っている(root ならsudo crontab -lも確認) - [ ] ログ(
grep CRON /var/log/syslogまたはjournalctl -u cron)に実行痕跡がある - [ ] コマンドとスクリプト内のパスがすべて絶対パスになっている
- [ ] 実行結果をファイルまたはメールで受け取れる
- [ ] 編集前の crontab を控えてある
コピペ用:cron 障害切り分けテンプレ
# 控えを取る(編集前に必ず) crontab -l > ~/crontab-$(date +%Y%m%d).bak # 登録確認 crontab -l sudo crontab -l # ログ確認 grep CRON /var/log/syslog journalctl -u cron -n 100 # 手動実行(実行ユーザーで) sudo -u user /path/to/script.sh