HerokuでEmbulkを動かすためにHerokuの Container Registry を利用する必要がありました。
Heroku上でDockerコンテナを動かすためにいくつかポイントがあるので後世のために共有します。
前提条件
以下のようなユースケースでの実装例になります。
他のユースケースでは使用するEmbulkのプラグインが異なると思いますが基本的な部分は大差ないはずです。
- Heroku上でEmbulkを実行する
-
Heroku Scheduler
を利用して日次実行する - 過去分のデータ移行の処理も必要
-
- S3のログファイルをBigQueryにロードする処理
- 記事の本題ではないのでEmbulkを実行するスクリプトなどは割愛しています
1. Dockerfileの記述例
S3のログファイルをBigQueryにロードする処理で以下の3つのプラグインを使用しています。
- embulk-input-s3
- embulk-output-bigquery
- embulk-parser-jsonl
FROM openjdk:8
RUN apt-get -y update && apt-get -y upgrade
RUN apt-get install bash
WORKDIR /app
# 本題から逸れるのでアプリケーションコードの配置などは省いています
RUN curl -o /bin/embulk --create-dirs -L "http://dl.embulk.org/embulk-latest.jar" && chmod +x /bin/embulk
RUN embulk mkbundle bundle
RUN echo "gem 'embulk-input-s3', '0.3.4'" >> bundle/Gemfile
RUN echo "gem 'embulk-output-bigquery', '0.4.4'" >> bundle/Gemfile
RUN echo "gem 'embulk-parser-jsonl', '0.2.0'" >> bundle/Gemfile
WORKDIR bundle
RUN embulk bundle
WORKDIR /app
ポイントになるのは以下の2点です。
特に2点目がハマりどころです。
- Embulkを
/bin
以下に配置することでパスの設定の手間を省く - mkbundle を使用してプラグインのgemのインストール先を指定する
mkbundleを使用しない場合に発生する問題について
HerokuにコンテナをデプロイしてEmbulkを実行すると以下のエラーが発生して実行できません。
2019-09-15 19:22:17.628 +0900 [INFO] (main): Gem's home and path are set by default: "/app/.embulk/lib/gems"
2019-09-15 19:22:22.575 +0900 [INFO] (main): Started Embulk v0.9.18
org.embulk.config.ConfigException: InputPlugin 's3' is not found.
org.jruby.proxy.org.embulk.config.ConfigException$Proxy1: Unknown input plugin 's3'. embulk/input/s3.rb is not installed. Run 'embulk gem search -rd embulk-input' command to find plugins.
ポイントになるのは以下の部分です。
Gem's home and path are set by default: "/app/.embulk/lib/gems"
Embulkはインストールされたプラグインを /app/.embulk/lib/gems
以下に探しにいくのですが
実際には /root/.embulk/lib/gems
以下に配置されます。
プラグインインストール時のログ
Gem plugin path is: /root/.embulk/lib/gems
ローカルで実行した場合にはこの問題は発生しないのでHerokuのDockerコンテナのデプロイ、実行環境の問題だと思われるのですが詳細なメカニズムは分かりません。
対応としては以下の2点が挙げられるのですが 1
の方がスマートですね。
-
mkbundle
を利用してプラグインのインストール場所を指定する - Dockerfileで
WORKDIR /root
にしてプラグイン、アプリケーションコードを全て/root
以下に配置する
なお、Embulkの実行は -b
オプションでプラグインのインストール先を指定します。
このケースの場合は以下のようになります。
embulk run -b /app/bundle /app/config.yml
2. Herokuへのコンテナのデプロイ
Heroku Scheduler を利用して日次実行する
という要件を満たすためには web
でデプロイする必要があります。
これはHerokuの仕様で詳しくは Heroku Schedulerは --type=web のDockerコンテナしか実行しない を参照ください。
heroku container:push web --app [APP_NAME]
heroku container:release web --app [APP_NAME]
一方でデバッグや同期実行のために worker
でもデプロイする必要があります。
どういうわけか web
でデプロイした方に heroku run bash
で接続すると1分間で強制切断されます。
HerokuのHTTPリクエストが1分でタイムアウトさせられる仕様が誤作動しているような印象です・
heroku container:push worker --app [APP_NAME]
heroku container:release worker --app [APP_NAME]
まとめると、スケジュール実行が必要な処理をHeroku上で行う場合は web
worker
の両方に同じコンテナをデプロイしなければなりません。
3. Dyno Typeについて
Embulkは実行時の消費メモリが大きいのでHerokuで実行するには Dyno Type
は最低でも standard-2x
は必要です。
Herokuへ接続する際や One-Off
実行する際は必ず --size
オプションを指定しましょう。
Herokuへのbash接続コマンド例
heroku run bash --type=worker --size=standard-2x --app [APP_NAME]