Posted at

Docker上でcronからrubyを実行しようとしてハマった

More than 3 years have passed since last update.

Docker上でrubyで作ったbotをcronで動かそうとしたらハマりました。


最終的なDockerfile

FROM ruby:latest

MAINTAINER ABCanG <abcang1015@gmail.com>

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

# timezone
RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

RUN mkdir -p /app
WORKDIR /app

COPY Gemfile /app/
COPY Gemfile.lock /app/
RUN bundle install --deployment

COPY . /app

RUN env > /env

CMD echo '30 * * * * cd /app; env - `cat /env` ruby ./script.rb' | crontab - && cron -f

以下の事を実行しています


  • cronをインストール

  • タイムゾーンを日本に変更

  • アプリをコンテナ内にコピーしてbundle install

  • dockerコンテナ内の環境変数をファイルに書き出し

  • cronで実行するスクリプトの登録とcronの実行

それぞれの説明は以下で


cronのインストール

ruby:latestはdebianなので、apt-getでcronをインストールします。


タイムゾーンを日本に変更

デフォルトではUTCになっているので日本時間に変更しています。

時間が関係ないスクリプトならスキップしても問題ないと思います。


アプリをコンテナ内にコピーしてbundle install

デプロイするので--deploymentを付けてbundle installしてます。


dockerコンテナ内の環境変数をファイルに書き出し

ハマリポイントその1です。

cronでは最低限の環境変数しか設定されません。

ruby:latestでは環境変数にbundleやその設定ファイルのパスを設定するため、cronでbundleを実行したときと挙動が変わってしまいます。

これを防ぐため、先に環境変数をファイルに書き出しておき、cronでスクリプトを実行するときに環境変数を利用するようにしています。


cronで実行するスクリプトの登録とcronの実行

ハマリポイントその2です。

echoの出力をcrontab -に流し込むことで設定します。

その後cron -fでcronを起動させています。

下のようにcronの設定は分けたかったのですが、どうも上手く動かないのでしぶしぶこの方法に。

何がマズイんでしょうね…(納得していない)

RUN echo '30 * * * * cd /app; env - `cat /env` ruby ./script.rb' | crontab -

CMD ["cron", "-f"]


おわりに

cronを使う時は注意が必要ですね。

もうちょっといい方法とかあれば教えてもらえるとうれしいです。