SakuraWi - BLog

WEBエンジニア。聴いたお話をまとめておく倉庫的な。スタックストックスタック!

【AWS lambda】RubyでlayerにGemfile, chromedriverをアップロードして使用する方法


AWS lambdaのlayerにRubyのGemfileとchromedriverをアップして利用する方法のまとめです。

ruby 2.5でスクレイピングさせるケースで利用するときにlambdaを使った際の構成になっています。

概要

  1. S3にlayerに利用するファイル(zip化)をアップロードする
  2. layerを新規追加する
  3. 関数に適用する

記事の順番的に、まずはchromedriverとheadless-chromiumをlayerにあげて、そのあとにgemfileを対応します。

AWS S3にzipをアップする

まずS3にbinaryファイル (chromedriverとheadless-chromium)をアップする必要があります。

S3経由でないと、重いファイルはlayerに追加できません。

S3に上げる際には、zipで圧縮しましょう。
chromedriverとheadless-chromiumについては、こちらの記事を参照しました。

f:id:Saku-Saku:20200430145516p:plain

bin配下をzipにします。

zip -r chrome.zip bin/

chrome.zipというファイル名に出力します。 bin/ 配下を対象にしてます。

S3には、適当にバケットを追加してデータをアップロードすればOKです。

AWS lambda layerに追加する

レイヤーは下記参照にして追加しましょう!

f:id:Saku-Saku:20200430145738j:plain

追加する際に、互換性のあるランタイムに適用した言語のverを指定します。

今回だとruby 2.5です。

f:id:Saku-Saku:20200430150605j:plain

追加ができたら、関数に適用していきます。

関数にlayerを適用する

関数にlayerを指定する際にランタイムの指定がないとlayerを選べません。

ARNというものでも指定できるようですが、ランタイムを合わせておいた方が安全そう。

また、layerは更新するとversionがかわるので、versionの指定も忘れずに。

読み込みを行う順番も指定できるようですが、今回は依存性はないので無問題だと思います。

実行する関数のコードの書き換え

今まではまとめてzipにdeployしていた関数の中からbin/ 配下を指定していたりしました。

そこをlayerで置いた部分へ参照先を変更します。

1. chromedriver などの読み込み

bin/chromedriver としていた部分を、書き換えます。

lambdaでは /opt 配下にライブラリとして参照できるようです。

参考
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-layers.html

Lambdaが実行されているディレクトリは、 /var/task

らしいのが理由みたいですね。

before

  service = Selenium::WebDriver::Service.chrome(path: 'bin/chromedriver')

  ...

  options = Selenium::WebDriver::Chrome::Options.new(binary: 'bin/headless-chromium')

after

  service = Selenium::WebDriver::Service.chrome(path: '/opt/bin/chromedriver')

  ...

  options = Selenium::WebDriver::Chrome::Options.new(binary: '/opt/bin/headless-chromium')

この辺はdriver_pathでも動きそうです。試してはいません。

あとは、zip化するときのコマンドも変更が必要です。

zip -r function.zip lambda_function.rb bin/ vendor/
zip -r function.zip lambda_function.rb vendor/ -x \*bin/\* 

-x \*bin/\* これで除外できるようです。
bin/を含めずにzipにします。

て思いましたけど、普通に

zip -r function.zip lambda_function.rb vendor/

でいいですねw

55MBくらいから、13.4MBに!いいですね。

テストして動作するかも確認しておきましょう。

疑問、localのdockerで試すときどうするの?

これ、AWS lambda上ではよいですけど、手元だとどうするんですかね。

samとかだとよしなにやってくれる...?

というか、layerの利用想定としては、ライブラリの外部出しに利用するみたいですね。

rubyだと、vendor 配下をlayerにして、 requireできるようにするイメージぽい。あってるかな?

...よし!やってみるか!!!

AWS lambdaでGemfileのlayer化をやってみた

zip -r gemfiles.zip vendor/

でvendor配下をzip化。

layerにしてアップします。

あれ、だめだ。

f:id:Saku-Saku:20200430164522p:plain

んー?

amazonのドキュメントでディレクトリ構成をチェック。

f:id:Saku-Saku:20200430164612j:plain

あれ!?bundle installしたときの構成となんか違うぞ。。。

ひとまず手作りしてみるか。-> ディレクトリ構成を修正したzipファイルを作成。

s3 upload -> レイヤー削除 -> 関数のレイヤー削除、適用 -> テスト

めっちゃ手間かかるw

amazonの指定通りにしたら実行できました。

zipファイルを展開するとこのようになります。

f:id:Saku-Saku:20200430165751j:plain

この辺をsamとか使うとよしなにやってくれるんだな、おそらく。

誰か、教えて!↓

https://twitter.com/KotaSakurawi

最終的に

uploadするファイルは lambda_function.rbのzipしたファイルだけになりました。

インラインで編集も可能になり、ファイルも1MBに!いいですね。

f:id:Saku-Saku:20200430170235j:plain

Gemfileは結構更新されるので、日々updateしてlayerにデプロイしていると依存問題で動かない関数がでたりしそうな気配もありますが、testかいとけって感じなんでしょうか。