動かざることバグの如し

近づきたいよ 君の理想に

kamalでcron設定をする方法

やりたいこと

Capistranoでwhenerverで簡単にcron設定できていたように、kamalでもcronの設定を簡単に行いたい。

しかし公式ドキュメントに項はあるが最低限の話しかなくて実際どうすればいいのかわからない。

詳細を書いてる記事がなかったのでメモ。

環境

  • kamal 2.7.0

手順

config/deploy.ymlにcron用のサーバーを追加する

servers:
  web:
    - ubuntu02.local
  cron:
    hosts:
      - ubuntu02.local
    cmd: bash -c "(env && cat config/crontab) | crontab - && cron -f"

bash -c "(env && cat config/crontab) | crontab - && cron -f はある種おまじないで、 「現在の環境変数を引き継いでconfig/crontabファイルの内容をスケジュールに登録し、そのスケジュールを実行するcronを起動する」をしている。 cron -f はフォアグラウンドの意味。

次に反映したいcronの内容をconfig/crontabに書く。テストに以下とする。

* * * * * bash -c "date >> /tmp/cronlog && date && mkdir /tmp/hoge" >/proc/1/fd/1 2>/proc/1/fd/2

>/proc/1/fd/1 2>/proc/1/fd/2 を出力先に設定している理由だが、Dockerのログで確認できるようにするため。

Dockerコンテナでは、通常、コンテナ起動時に実行されるメインプロセス(PID 1)の標準出力と標準エラー出力だけが docker logs に送られる。 今回、cronは別のプロセスとしてジョブを実行するから、その出力が直接 docker logs には現れない。 そのため、cronジョブの出力をコンテナのメインプロセス(PID 1)の出力にリダイレクトすることで出力をコンテナのログに直接リダイレクトできる。

確認

設定チェック

kamal app exec --interactive --reuse -r cron crontab -l

と実行して

HOSTNAME=ubuntu02.local-56d8f9078cb1
(略)
_=/usr/bin/env
* * * * * bash -c "date >> /tmp/cronlog && date && mkdir /tmp/hoge" >/proc/1/fd/1 2>/proc/1/fd/2

環境変数とconfig/crontabの内容が反映されていればOK

ログチェック

kamal app logs -r cron -f

2025-08-24T09:44:01.340454537Z Sun Aug 24 18:44:01 JST 2025
2025-08-24T09:44:01.341768977Z mkdir: cannot create directory '/tmp/hoge': File exists
2025-08-24T09:45:01.351988114Z Sun Aug 24 18:45:01 JST 2025
2025-08-24T09:45:01.352909314Z mkdir: cannot create directory '/tmp/hoge': File exists

と出ていればOK