Edited at

ClockworkとDockerでRubyスクリプトの定期実行


これは何?



  • Ruby を定期実行したい!


  • Ruby には定期実行が簡単に実行できる Clockwork がある!


  • Docker を使ってもっともっと簡単に実行できるようにしたい!(cron を導入したりとか面倒なこともしたくない)

ということでしてみましたのでそのご紹介と知見共有です


Clockworkとは

Ruby の定期実行用 Gem

定期実行といえば cron が有名であり、さらに Ruby で定期実行となれば whenever が有名かと思います。

Clockwork を使えば上記のツールを使うように簡単に定期実行を行う事ができます。

細かな話は以下のような記事や上記の公式ドキュメントをご確認ください


試してみる

上記のリポジトリに確認できるコードを置いています。自由に使ってください。

※もちろん Docker の環境が必要です


1.ソースコードのクローン

上記ソースコード一式を clone してきてください

git clone https://gitlab.com/sample-by-toririn/clockwork_docker.git


2.イメージの作成

以下のコマンドで Docker Image を作成してください

docker build -t clock_test .


3.コンテナの作成

以下のコマンドでコンテナを作成してください

docker run --name clock_test -v `pwd`:/usr/src/app -d clock_test


4.ログの確認

以下のコマンドでログを確認してください

docker logs -f clock_test

以下のようなログが次々と出て入れば無事定期実行が動いています

I, [2019-08-10T00:52:35.005344 #1]  INFO -- : Triggering 'test'

2019年08月10日の00時52分35秒だよ!
I, [2019-08-10T00:52:35.005344 #1] INFO -- : Triggering 'test'
2019年08月10日の00時52分38秒だよ!

※時間は実行した時間が表示されるかと思います


5.ちょっとした修正

コンテナ作成時に -v オプションをつけていたので直接コードを修正してください。

修正ができればコンテナを再起動することで反映がされます

docker restart clock_test


仕組み

仕組みというほどのことはありませんが、単純に Ruby の公式イメージに Clockwork をインストールし実行をしているだけです。


Dockerfile

以下が Dockerfile です

FROM ruby:2.6.3-slim-stretch

ENV LANG C.UTF-8
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY . /usr/src/app
RUN bundle install

CMD ["bundle", "exec", "clockwork", "config/clock.rb"]

5行目でイメージを作成するときにソースコード一式をイメージに入れています。

6行目で clockwork のインストールを行なっています

最後にコマンドで clockwork を実行しています


config/clock.rb

以下が clockwork の設定ファイルです(一部省略)

# 定期実行で利用するクラスの読み込み

require_relative '../lib/clock_test'

# Clockworkを利用するためにモジュールを読み込み
include Clockwork
# 定期実行で利用するクラスの読み込み
include ClockTest

# Clockworkの設定値
configure do |config|
# 日本時間のタイムゾーンを設定
config[:tz] = "Asia/Tokyo"
end

# ...省略

# 3秒に1回実行
every(3.seconds, "test") do
Foo.new.run
end

説明は書いている通りです。

clockwork の設定側でタイムゾーンに日本時間を設定しています。こちらがなければ UTC で実行されることになります。

この設定もなくしたければ Docker Image のシステム時間を日本時間に変更することでも対応できます

ログで確認できたのは3秒に1回実行される設定をしていたところです


Foo.new.run

以下が Foo クラスの中身です

require_relative "logger"

module ClockTest
class Foo
def run
current_time = Time.new.strftime("%Y年%m月%d日の%H時%M分%S秒だよ!")
Logger.info(current_time)
end
end
end

ただ現在時刻をとってきてログに出しているだけです。

しかし DockerRubyTime クラスを使うのには注意が必要です


Ruby が利用するタイムゾーンを設定する

以下が設定を行なっている initialize.rb の中身です

require "time"

# 時間を日本時間にする
ENV["TZ"] = "Asia/Tokyo"

RubyTZ という環境変数にタイムゾーンの地域を設定していれば、そのタイムゾーンを使ってくれます。

もし上記の設定がなければシステムのタイムゾーンが使われます。

だいたいのピュアな Docker ImageUTC になっているので、上記の設定を追加して日本時間のタイムゾーンを設定しています。

これで Time.new で取得される時刻オブジェクトは日本時間のものになりました。


補足

ここで設定しなくても DockerfileENV の設定を記載することでも日本時間に変更することは可能です!

参考: Rubyのタイムゾーン


まとめ



  • Docker + Ruby で定期実行処理はとても簡単にできる