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を使う時は注意が必要ですね。
もうちょっといい方法とかあれば教えてもらえるとうれしいです。