トラブルシューティング · Docker

Docker コンテナの cron が動かない?実際に効く修正方法

Docker コンテナ内の cron がサイレントに失敗する理由 — PID 1、環境変数の消失、MTA なし — とそれぞれの修正方法。

コンテナ内で cron を動かすと、コンテナは通常の VM ではないため問題が起きやすいです。よくある原因を修正方法と合わせて紹介します。

1. cron が PID 1 として動いていない

コンテナはフォアグラウンドプロセスを1つだけ実行します。CMD でアプリを起動した場合、cron は決して起動しません。CMDcron でも、デーモン化するためすぐに終了することがあります。フォアグラウンドで実行してください。

# Debian/Ubuntu ベース
CMD ["cron", "-f"]

cron とアプリを両方動かすには、小さなスーパーバイザー(supervisords6)またはプロセスマネージャーを使ってください — シェルの CMD でのバックグラウンド化には頼らないでください。

2. cron では環境変数が消える

これが最大の原因です。Docker は環境変数を PID 1 に注入しますが、cron はクリーンな環境でジョブを起動するため、DATABASE_URL や API キーが消えています。起動時にコンテナの環境変数をファイルにダンプして、ジョブで source してください。

CMD printenv | sed 's/^\(.*\)$/export \1/' > /etc/container.env && cron -f
# crontab 内で
0 * * * * . /etc/container.env && /app/run.sh

3. crontab には正しいフォーマットと末尾の改行が必要

システム crontab の行にはユーザー列が必要で、ファイルは改行で終わらないと最後のジョブが無視されます。

# /etc/cron.d/app  — 「root」ユーザーフィールドに注意
0 2 * * * root /app/run.sh >> /var/log/cron.log 2>&1
COPY app-cron /etc/cron.d/app
RUN chmod 0644 /etc/cron.d/app && crontab /etc/cron.d/app

4.「cron がメールを送れない」— MTA がない

よくあるパターン: コンテナの crontab が出力をメールしようとしても MTA がないため、ジョブが「失敗」しているように見えます。ローカルメールに依存しないでください。docker logs に記録されるよう stdout にリダイレクトしてください。

0 2 * * * root /app/run.sh > /proc/1/fd/1 2>/proc/1/fd/2

5. 出力を確認する

docker logs -f <container>
docker exec -it <container> sh -c "crontab -l"

本当の問題: コンテナは再起動し、cron は忘れる

再デプロイ、OOM kill、クラッシュループ — これらはどれもコンテナ内の cron を停止させる可能性があり、何も教えてくれません。コンテナの外から監視することが唯一の信頼できるシグナルです。

ジョブが成功したときにハートビート URL に ping してください。コンテナがダウンしているかジョブが発火を停止した場合、ping が欠落してアラートが届きます。

HEALTHCHECK --interval=5m --timeout=10s \
  CMD curl -fsS https://ping.steadycron.com/<your-ping-token> || exit 1