これは何?
-
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
ただ現在時刻をとってきてログに出しているだけです。
しかし Docker
で Ruby
の Time
クラスを使うのには注意が必要です
Ruby
が利用するタイムゾーンを設定する
以下が設定を行なっている initialize.rb
の中身です
require "time"
# 時間を日本時間にする
ENV["TZ"] = "Asia/Tokyo"
Ruby
は TZ
という環境変数にタイムゾーンの地域を設定していれば、そのタイムゾーンを使ってくれます。
もし上記の設定がなければシステムのタイムゾーンが使われます。
だいたいのピュアな Docker Image
は UTC
になっているので、上記の設定を追加して日本時間のタイムゾーンを設定しています。
これで Time.new
で取得される時刻オブジェクトは日本時間のものになりました。
補足
ここで設定しなくても Dockerfile
で ENV
の設定を記載することでも日本時間に変更することは可能です!
参考: Rubyのタイムゾーン
まとめ
-
Docker
+Ruby
で定期実行処理はとても簡単にできる