いつもありがとうございます。
「cronでバックアップを自動化したけど、本当にちゃんと動いているのか不安...」
「cronジョブが失敗していたのに、誰も気づけなかった」
こういう経験、ありませんか?
実は、cronには致命的な弱点があります。それは「起動は保証するけど、成功は保証しない」ということです。
この記事では、15年以上サーバーを運用してきた経験から、cronジョブの「動いてるつもり」がなぜ一番怖いのか、そしてその落とし穴を防ぐための3つの対策を具体的なスクリプト付きで解説します。
私が経験した「2ヶ月間バックアップが取れていなかった」事件
新人SEの頃の話です。
ある日、上司から「バックアップから戻してくれ」と言われました。
保存先のディレクトリを開いた瞬間、自分の目を疑いました。
最新のバックアップファイルの日付が、2ヶ月前だったんです。
毎晩3時にバックアップを取るcronジョブを、ちゃんと設定したはずでした。設定した日に動作確認もしました。
でも、2ヶ月前のディスク構成変更で、保存先のパスが変わっていたんです。
スクリプトは毎晩起動していました。毎晩エラーを吐いていました。でも、誰もそのエラーに気づかなかった。
幸いにも、手動で取っていた古いバックアップが残っていて、なんとか復旧できました。しかし、あの時の冷や汗は今でも覚えています。
この経験から学んだことは1つ。
「動いてるつもり」が一番怖い、ということです。
サービスが止まれば、すぐ気づけます。監視アラートが鳴れば、対応できます。
でもcronジョブの失敗は違います。バックアップが必要になった時、レポートを求められた時、ログの整理が必要になった時。「結果を使う日」に初めて「動いてなかった」と気づくんです。
しかも、そういう時はたいてい緊急事態です。一番困っている時に、頼みの綱が切れていたと分かる。
セミナーで3,100名以上を指導してきた中でも、「cronジョブが知らない間に止まっていた」という相談は本当に多いです。
cronの「弱点」を正しく理解する
まず、cronが何を保証して何を保証しないのか、正確に理解しておきましょう。
cronの仕事は「指定した時間に、指定したコマンドを起動する」。これだけです。
・コマンドが正常に終了したか
・ファイルがちゃんと生成されたか
・期待通りの結果になったか
これらはすべてcronの管轄外です。
cronのログ(/var/log/cron)を見ても、「起動した」という記録しか残りません。実際に確認してみましょう。
# cronログで直近の実行記録を確認する sudo grep CRON /var/log/cron | tail -5 # 出力例 Mar 12 03:00:01 server01 CROND[12345]: (root) CMD (/root/backup.sh) Mar 12 03:00:01 server01 CROND[12346]: (root) CMD (/root/cleanup.sh)
backup.shが成功したのか失敗したのかは、一切記録されていません。
だから、cronに任せっぱなしにすると「動いてるつもり」の状態になるんです。
では、どうすればいいのか。対策は3つあります。
対策1|ログに残す
1. リダイレクトの基本(>> と 2>&1)
まず最低限やるべきことは、cronジョブの出力をログファイルに残すことです。
crontabの設定で、コマンドの末尾にリダイレクト記号を追加します。
# NG:出力を残さない(デフォルトの状態) 0 3 * * * /root/backup.sh # OK:出力をログファイルに残す 0 3 * * * /root/backup.sh >> /var/log/backup.log 2>&1
・>> : ログファイルに追記する(> だと毎回上書きされてしまう)
・2>&1 : エラー出力(2)を標準出力(1)と同じ場所に流す
「2>&1」がないと、正常時のメッセージは残るのに、肝心のエラーメッセージが消えてしまいます。
cronジョブのログには必ず「2>&1」を付けてください。これがないと、失敗した時に何が起きたか追えません。
2. 実践例:バックアップスクリプトにログを追加
実際のバックアップスクリプトを例に、ログ出力を組み込む方法を見てみましょう。
#!/bin/bash # バックアップスクリプト(ログ出力付き) LOGFILE="/var/log/backup.log" BACKUP_DIR="/backup/db" DATE=$(date +%Y%m%d_%H%M%S) echo "===== バックアップ開始: $(date) =====" >> "$LOGFILE" # データベースのバックアップを取得 /usr/bin/pg_dump mydb > "${BACKUP_DIR}/mydb_${DATE}.sql" 2>> "$LOGFILE" if [ $? -eq 0 ]; then echo "[SUCCESS] バックアップ完了: mydb_${DATE}.sql" >> "$LOGFILE" else echo "[ERROR] バックアップ失敗" >> "$LOGFILE" fi echo "===== バックアップ終了: $(date) =====" >> "$LOGFILE"
ただし、ログを残すだけでは足りません。
なぜなら、ログは「見に行かないと気づけない」からです。「毎日ログを確認しよう」と決めても、1週間もすれば見なくなります。これは人間の性質として仕方のないことです。
だから、次の対策が必要になります。
対策2|失敗時に通知する
1. exit codeでチェックする仕組み
Linuxのコマンドは、実行結果を「終了コード(exit code)」で返します。
・0 : 成功
・0以外 : 失敗(1, 2, 127など、エラーの種類によって異なる)
この終了コードを使って、「失敗した時だけ通知を飛ばす」仕組みを作ります。
考え方はシンプルです。毎日「成功しました」と通知されても、すぐに読まなくなります。「失敗した時だけ」通知する。これだけで「動いてるつもり」問題の大部分を防げます。
2. メール通知スクリプトの例
実際のスクリプト例を見てみましょう。
#!/bin/bash # バックアップスクリプト(失敗時メール通知付き) LOGFILE="/var/log/backup.log" BACKUP_DIR="/backup/db" DATE=$(date +%Y%m%d_%H%M%S) ADMIN_MAIL="admin@example.com" echo "===== バックアップ開始: $(date) =====" >> "$LOGFILE" # データベースのバックアップを取得 /usr/bin/pg_dump mydb > "${BACKUP_DIR}/mydb_${DATE}.sql" 2>> "$LOGFILE" if [ $? -ne 0 ]; then # 失敗時:ログに記録 + メール通知 echo "[ERROR] バックアップ失敗: $(date)" >> "$LOGFILE" echo "バックアップが失敗しました。 サーバー: $(hostname) 日時: $(date) ログ: $LOGFILE" | mail -s "[ERROR] バックアップ失敗 - $(hostname)" "$ADMIN_MAIL" else echo "[SUCCESS] バックアップ完了: mydb_${DATE}.sql" >> "$LOGFILE" fi
このスクリプトなら、失敗した時だけメールが飛びます。「通知が来ない=正常」という状態を作れるので、日常的にログを確認する必要がなくなります。
メール送信には mail コマンド(mailx パッケージ)を使っています。サーバーにPostfixなどのMTAが設定されている必要があります。
対策3|週次サマリーで「ハートビート確認」
1. 定期的に「正常に動いているか」を確認する習慣
「失敗したら通知する」仕組みを作った。通知が来ない。よし、正常だな。
...本当にそうでしょうか。
・メールサーバーが止まっていたら?
・cronジョブ自体がそもそも起動しなくなっていたら?
「通知が来ない」理由が「成功しているから」ではなく「通知できない状態だから」というケースがあります。
これを防ぐのが「週次サマリー」です。週に1回だけ、「今週のバックアップはすべて成功しました」というサマリーメールを送ります。
#!/bin/bash # 週次バックアップサマリー(毎週月曜9時に実行) LOGFILE="/var/log/backup.log" ADMIN_MAIL="admin@example.com" # 過去7日間のログからSUCCESSとERRORの件数を集計 SUCCESS=$(grep -c "\[SUCCESS\]" "$LOGFILE" 2>/dev/null || echo 0) ERROR=$(grep -c "\[ERROR\]" "$LOGFILE" 2>/dev/null || echo 0) SUBJECT="[週次レポート] バックアップサマリー - $(hostname)" BODY="サーバー: $(hostname) 期間: $(date -d '7 days ago' +%Y/%m/%d) ~ $(date +%Y/%m/%d) 成功: ${SUCCESS}件 失敗: ${ERROR}件 このメールは週次の生存確認です。 このメール自体が届かなくなったら、通知の仕組みに問題が起きています。" echo "$BODY" | mail -s "$SUBJECT" "$ADMIN_MAIL"
# crontab -e で以下を追加 # 毎週月曜の朝9時に週次サマリーを送信 0 9 * * 1 /root/weekly_summary.sh
「通知が来ない」のが「正常だから」なのか「壊れているから」なのか。この区別ができるかどうかで、運用の安心感がまったく変わりますよ。
私が現場でよく見かけるのが、失敗通知の仕組みは作ったのに、メールサーバーの設定変更で通知が届かなくなっていたケースです。週次サマリーがあれば「月曜にメールが来ない」時点で異常に気づけます。
よくある質問
Q. cronジョブが動いているかどうか、手っ取り早く確認する方法はありますか?
cronログを確認するのが一番手軽です。
# cronの実行ログを確認する sudo grep CRON /var/log/cron | tail -10
Q. mail コマンドが使えない環境ではどうすればいいですか?
mail コマンドが使えない場合は、curl を使ってSlackやChatworkなどのチャットツールに通知を送る方法があります。
# Slack Webhook を使った通知例 curl -s -X POST -H 'Content-type: application/json' \ --data '{"text":"[ERROR] バックアップ失敗 - サーバー名"}' \ https://hooks.slack.com/services/YOUR/WEBHOOK/URL
Q. cronジョブが多すぎて、どれにログや通知を入れるべきか判断できません
まずは「失敗した時の影響が大きいジョブ」から優先してください。
・バックアップ系のジョブ(データ消失に直結する)
・ログローテーション(ディスク容量に直結する)
・セキュリティ関連(脆弱性スキャン、証明書更新など)
すべてのジョブに一度に導入する必要はありません。影響度の高いものから順番に対策を入れていけば、運用は確実に安定していきます。
まとめ
| 対策 | やること | 効果 |
|---|---|---|
| 対策1:ログに残す | コマンド末尾に >> /var/log/xxx.log 2>&1 を追加 |
「何が起きたか」を後から追える |
| 対策2:失敗時に通知する | スクリプト内で終了コード($?)を判定し、失敗時だけメール送信 | ログを毎日見に行かなくても失敗に気づける |
| 対策3:週次サマリー | 週1回「今週の結果」をまとめて送信 | 通知の仕組み自体が生きているか確認できる |
cronの「正しい設定方法」を体系的に学びませんか?
cronは便利ですが、正しく使わないと「動いてるつもり」の罠にはまります。運用の基本を体系的に学びましょう。
ネットの切れ端の情報をコピペするだけでなく、現場で通用する安全なLinuxサーバー構築の「型」を体系的に身につけたい方へ、『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼントしています。
「独学の時間がもったいない」「プロから直接、現場の技術を最短で学びたい」という本気の方には、2日で実務レベルのスキルが身につく【初心者向けハンズオンセミナー】も開催しています。
P.S
セミナーでは、cronの設定だけでなく、「運用で失敗しないための考え方」も実践的に学べます。構築して終わりではなく、その後の運用まで見据えた学習ができるのがセミナーの強みです。
【Linuxセミナー】リナックスマスタープロセミナー
[「とりあえず再起動」が危険な理由|プロのトラブル初動を現役講師が解説]
[Linuxサーバー構築の全体像|初心者が知っておくべき手順と現場のリアル]
登録10秒/自動返信でDL/合わなければ解除3秒
- 次のページへ:Linuxサーバーのパスワードが甘いとどうなる?SSH攻撃の実態と対策
- 前のページへ:Linuxの将来性を現役エンジニアが解説|2026年以降も需要が伸びる理由
- この記事の属するカテゴリ:Linux学習ガイドへ戻る
