lambda
Embulk
EmbulkDay 21

embulk と AWS Lambda でサーバーレスデータ連携

More than 1 year has passed since last update.

Embulk Advent Calendar 2015 の21日目の投稿になります。

データ連携したいけどそこまで金は出せない

業務システムを開発しているとサービスAとサービスXのデータを連携したいという要望が、それこそ山のように出てきます。お客様はそれぞれ自分たちの業務システムをお持ちですし、それを我々のサービスXに接続して活用したいというのは自然な欲求です。
で、「なるほどなるほど承りました。ではデータ連携用のプログラム一式でXXXX万円、サーバー代にXXX万円、それを弊社データセンター内に配備しまして年間XX万円の保守費をいただきます」みたいな事をいうと「おいおい、お前のところは月額X千円がウリやったんじゃないんか!」と残念そうにキャンセルされるわけです。個別プログラムの開発と運用というのはそれだけお金がかかる。
お客様とそういう話を直接したことはないので想像なんですが、だいたい合ってると思う。

前説を書いていると延々としょうもない話で文字数を消費してしまうので簡単に。

モチベーション

  • embulk は input と output がプラガブルになっており、いろいろなシステムとの接続性が良い。
    • サードパーティー製のプラグインもどんどん出てきている
    • TD社がスポンサード(というか主体として開発)しているOSSなので勢いがある(主観)
  • AWS Lambda はプログラム実行時間だけで課金されるフルマネージドな計算資源提供サービス。
    • なのでサーバー構築・運用の手間削減が期待できる。
    • 最近 Scheduled Event の搭載でバッチ実行基盤としての芽も出てきた。
    • (5分の制限は辛いけども)

みたいな現状がある。なので

  • AWS Lambda 上で embulk を動かす

というアイデアが出てくる。

しかし、embulkは色々魔術的な構造をしているので一筋縄では行かない。
というわけで、AWS Lambda 上で実行できるバイナリを簡単に作成するためのパッケージャを開発しました。

embulk-awslambda-packager

https://github.com/mitoma/embulk-awslambda-packager

embulk-awslambda-packager は gradle script で書かれた、embulk の AWS Lambda 用パッケージングツールです。
なぜわざわざ単体のパッケージャが必要になったのか。embulk は、それそのものは jar として配布されており jar に含まれる EmbulkEmbed を実行してやれば比較的簡単に AWS Lambda 上で実行することは可能なのですが、そのプラグイン'sは rubygems のエコシステムに乗っかっているという変態的な構成をとっており、プラグイン含めて AWS Lambda 上で動かすのには面倒なパッケージング作業が必要でした。
ていうか過去形で書いているけどそういうことやってる人見たことない。多分ほとんどの人は AWS Lambda 上では動かないとあきらめている。

なので簡単にできるようにすればいろいろ捗るという目算があった。

使い方

使うためのステップは以下になる。

  1. S3の読み込み・書き込み権限のあるAWS Lambda用のロールを作る
  2. パッケージャを使ってembulkをAWS Lambda向けにパッケージングする
  3. パッケージしたファイルを S3 にアップロードする
  4. Lambda 関数の設定をする
  5. 動く。めでたい。

このなかで、説明しないといけないのは 2, 3, 4なのでその説明をする。

2.パッケージャを使ってembulkをAWS Lambda向けにパッケージングする

パッケージャをチェックアウトしてそのディレクトリに移動する。

git clone https://github.com/mitoma/embulk-awslambda-packager.git
cd embulk-awslambda-packager

次に、パッケージングしたい設定を準備して以下のパラメータを指定する。

./gradlew clean build \
 -PembulkPlugins="[使いたいプラグインをスペース区切りで指定]" \
 -PgemsS3BucketName="[プラグインバイナリの S3 バケット名]"
 -PgemsS3Key="[プラグインバイナリのS3上のパス]" \
 -PembulkConfig="[コンフィグファイルの絶対パスを指定]" \
 -PuseExternalConfig="[↑のコンフィグを使わず、S3のコンフィグを使いたい場合にtrueを指定]" \
 -PexternalConfigS3BucketName="[コンフィグファイルのS3上のバケット名]" \
 -PexternalConfigS3Key="[コンフィグファイルのS3上のパス]" \
 -PoverWriteExternalConfig="[S3上のコンフィグを実行完了後上書きするときtrueを指定]"

embulkPlugins は標準添付以外のプラグインが必要なときに指定する。
gemsS3BucketName, gemsS3Key はプラグインのバイナリをS3のどこに置くか決めて値を指定してください。
useExternalConfig が true の時は externalConfigS3BucketName, PexternalConfigS3Key の2つの設定が必要。overWriteExternalConfig を使うことで -o オプションを使った時のように上書きすることができる。
useExternalConfig が falseの時は embulkConfig を指定してやる必要がある。

で、実行すると ./build/distribution 以下に awslambda.zip と gems.zip というものが生成されます。awslambda.zip は AWS Lambda で実行するための関数が含まれたバイナリで gems.zip は実行時に必要なプラグインのバイナリです。useExternalConfig が false の場合は gems.zip にconfig.yml も同梱されます。

3. パッケージしたファイルを S3 にアップロードする

生成された awslambda.zip と gems.zip を S3 にアップロードします。awslambda.zip は作成したロールの権限が及ぶ範囲ならS3のどこにアップしても構いません。gems.zip は gemsS3BucketName, gemsS3Key で指定した場所にアップしましょう。

4. Lambda 関数の設定をする

Runtime Java8 で Lambda 関数を作成します。
コードは Upload a .ZIP from Amazon S3 で先ほどアップした awslambda.zip を指定します。
handler には in.tombo.embulk.AwsLambdaExecutor::executeByScheduledEvent を指定します。
MemoryやTimeoutは要件に応じて適当に指定すればいいでしょうが、少なくとも512MB、2分程度を最小値として見ておくのがよいでしょう。

5. 動く。めでたい。

Test Event として Scheduled Event を指定し、実行すると設定に間違いがなければ動くでしょう。
今のところ開発して動作確認しているのは ScheduledEvent だけですが handler にin.tombo.embulk.AwsLambdaExecutor::executeByS3Event を指定すれば S3 Event も補足して実行できると思います。

現状の課題

現状としては以下の課題があるものの、自分一人の頭で考え続けていても答えが出るものでもないので一旦公開して周囲の反応をみて考えていきたいと思っています。

  • 本当に embulk + AWS Lambda のユースケースがあるのか
  • Lambda の5分縛りで使い物になるか
  • いろいろな連携に対して設定例を示せていない
  • Scheduled Event 以外の AWS Lambda のトリガーへの対応不足

その他、謝辞とか宣伝的なもの

embulk-awslambda-packager はサイボウズ株式会社の2015年度ハッカソンで開発されました。ハッカソンの成果を個人アカウントで公開することを許可していただいた事に感謝します。
もともとは kintone というサイボウズ株式会社のクラウドサービスと他システムで間でサーバーレスデータ連携するために embulk と AWS Lambda 使えないかというモチベーションが元となっています。

rubygems には非公開ですが kintone 向けの embulk プラグイン( https://github.com/mitoma/embulk-output-kintone )も開発中ですので、これもまたの機会に紹介できたらと思います。