AWS lambdaのlayerにRubyのGemfileとchromedriverをアップして利用する方法のまとめです。
ruby 2.5でスクレイピングさせるケースで利用するときにlambdaを使った際の構成になっています。
概要
- S3にlayerに利用するファイル(zip化)をアップロードする
- layerを新規追加する
- 関数に適用する
記事の順番的に、まずはchromedriverとheadless-chromiumをlayerにあげて、そのあとにgemfileを対応します。
AWS S3にzipをアップする
まずS3にbinaryファイル (chromedriverとheadless-chromium)をアップする必要があります。
S3経由でないと、重いファイルはlayerに追加できません。
S3に上げる際には、zipで圧縮しましょう。
chromedriverとheadless-chromiumについては、こちらの記事を参照しました。
bin配下をzipにします。
zip -r chrome.zip bin/
chrome.zipというファイル名に出力します。
bin/
配下を対象にしてます。
S3には、適当にバケットを追加してデータをアップロードすればOKです。
AWS lambda layerに追加する
レイヤーは下記参照にして追加しましょう!
追加する際に、互換性のあるランタイムに適用した言語のverを指定します。
今回だとruby 2.5です。
追加ができたら、関数に適用していきます。
関数に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にしてアップします。
あれ、だめだ。
んー?
amazonのドキュメントでディレクトリ構成をチェック。
あれ!?bundle installしたときの構成となんか違うぞ。。。
ひとまず手作りしてみるか。-> ディレクトリ構成を修正したzipファイルを作成。
s3 upload -> レイヤー削除 -> 関数のレイヤー削除、適用 -> テスト
めっちゃ手間かかるw
amazonの指定通りにしたら実行できました。
zipファイルを展開するとこのようになります。
この辺をsamとか使うとよしなにやってくれるんだな、おそらく。
誰か、教えて!↓
https://twitter.com/KotaSakurawi
最終的に
uploadするファイルは lambda_function.rb
のzipしたファイルだけになりました。
インラインで編集も可能になり、ファイルも1MBに!いいですね。
Gemfileは結構更新されるので、日々updateしてlayerにデプロイしていると依存問題で動かない関数がでたりしそうな気配もありますが、testかいとけって感じなんでしょうか。