ながたのメモ帳

Dockerのubuntuでcronを起動する

2022年3月16日 公開読了 約5分

##TL;DR

Docker の ubuntu イメージで cron が動作せずに悩んでる人は、以下のように変更することで、動作させることができる。

最後のCMDはやめて、RUN cron -f &とかに変更しても大丈夫。

DOCKERFILE
コピーコピー済みDOCKERFILE
FROM ubuntu:18.04

RUN apt-get update && apt-get install cron

RUN echo '* * * * * echo Hello World >  /var/log/cron.log' > /etc/cron.d/crontab

RUN chmod 0644 /etc/cron.d/crontab

RUN /usr/bin/crontab /etc/cron.d/crontab

CMD ["cron", "-f"]

これはかなり古い記事です。当時このサイトは Docker の中で Hugo を動かしていて、その定期処理のために cron が必要でした。今はもう Hugo も使っていないし、cron で rebuild を回すこともしていないので、私自身はこの構成を使っていません。それでも「Docker の ubuntu で cron が動かない」で困る人はまだいそうなので、そのまま残しておきます。

##なぜ困ったか

当時このサイトは、Docker 内で Hugo を使いサーバーを建てて起動していました。

ちょうどメインページに GitHub の API から取得した repo 情報を表示するところがあったのですが、これを定期的にリフレッシュしたくて cron を使うことにしました。

static フォルダ内に API から取得した json を保存しておくと、それが変更されたときに rebuild されるので最新の情報にしておくことができるというわけです。

そのため、cron を用いて

CRONTAB
コピーコピー済みCRONTAB
# 毎時0分にAPIから取得したjsonを保存する
0 * * * * wget -O - "https://api.github.com/users/nagataaaas/repos?type=owner&sort=updated&per_page=100" --no-check-certificate >  /static/github_repos.json

みたいなものを設定することで、リフレッシュ出来るわけです。

しかし、(これは知らなかったんですが)Docker 内ではデフォルトで cron を使えません(少なくとも ubuntu:18.04 では)。

そのため、いろいろ試したんですが、cron がどうにも実行されない?

漁りに漁ってようやく見つけたのがこのリポジトリです。

t
thelebster/docker-cron
An example of running cron job in a docker container.。
github.com

これを見つけるまでに、私は以下のようなものを試して上手くいきませんでした

DOCKERFILE
コピーコピー済みDOCKERFILE
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y cron --no-install-recommends

# setting cron
RUN echo '0 * * * * wget -O - "https://api.github.com/users/nagataaaas/repos?type=owner&sort=updated&per_page=100" --no-check-certificate >  /static/github_repos.json' >> /etc/crontab
RUN cron -f &

だったり

DOCKERFILE
コピーコピー済みDOCKERFILE
FROM ubuntu:18.04

RUN apt-get update && apt-get install -y cron --no-install-recommends

RUN /etc/init.d/cron start
RUN crontab -l > /crontab.txt
RUN echo '0 * * * * wget -O - "https://api.github.com/users/nagataaaas/repos?type=owner&sort=updated&per_page=100" --no-check-certificate >  /static/github_repos.json' >> /crontab.txt
RUN crontab /crontab.txt
RUN rm /crontab.txt

具体的にどれが原因なのかはわかっていませんが、考えられる問題点は

  • cron インストール時に --no-install-recommends オプションを指定している
  • /etc/cron.d/crontab の権限が違う?
  • /usr/bin/crontab 自体の実行をしていない

とかですかね?

私は Linux は門外漢なのであまりよくわからないですが、--no-install-recommends オプションを指定すると正しく動作しない場合があるのでしょうか。。。

とにかく、cron を動かすためには、このようにしなければならないということでした。

##追記: 今はどうしているか

冒頭にも書いた通り、今はもうこのサイトで Hugo も cron も使っていません。

そもそもの話として、「コンテナの中で cron を回す」という発想自体があまり筋が良くなかったな、というのが今の感想です。

  • コンテナは基本的に1プロセス1コンテナが原則なので、cron -f を CMD にしてその裏でアプリを動かす、みたいな構成はどうしても歪になる
  • cron のログがコンテナの標準出力に出てこないので、失敗しても気づけない(実際、当時これで何回か静かに死んでいました)
  • そもそも定期実行するだけなら、コンテナの外にその仕組みがあることの方が多い

定期的に何かを実行したいだけなら、GitHub Actions の schedule だったり、ホスト側の cron や systemd timer だったり、マネージドなスケジューラだったりに任せて、コンテナは「呼ばれたら1回動いて終わる」ものにしておく方が、後々の自分が楽です。

とはいえ、どうしてもコンテナの中で cron を動かしたい場面はあると思うので、その時は上の TL;DR を使ってください。