Lambda上でsnowflake-connector-pythonとPandasを用いてデータ取得を行ってみた
はじめに
好物はインフラとフロントエンドのかじわらゆたかです。 同僚からLambda上でsnowflake-connector-pythonとPandasを動かしたいんだけどちょっと困ってるんだよねって話をされました。
普通にLambda Layerの構築をしようとしているだけかと思い、自分でもLambda Layerを構築しようとしたところで理由を把握しました。
docker run --rm -v $(pwd):/var/task amazon/aws-sam-cli-build-image-python3.8:latest pip install "snowflake-connector-python[pandas]" -t python/lib/python3.8/site-packages/ zip -r lambda_layer.zip ./python
上記のようなコマンドで構築してみるとわかるのですが、Lambda layer用のzipのサイズが大きすぎる感があります。
-rw-r--r-- 1 kajiwarayutaka staff 138M 2 11 03:52 ./lambda_layer.zip
Lambda の制限事項としてデプロイパッケージは解凍・レイヤーを含んで250Mという制限があります。 これでは上限に引っかかってしまいそうなのでなにか別のアプローチを考える必要がありそうです。
LambdaLayerで配置が難しいときに取れそうなアプローチ
デプロイパッケージの制約に引っかかりそうな場合に取れそうなアプローチを列挙してみました
- EC2で動かす
- ECS(Fargate)で動かす
- AWS Batchで動かす
- Glue(Python SHell)で動かす
- Lambdaのコンテナイメージサポートを用いて動かす
今回はSaaSであるSnowflakeへのアクセスが目的なのもありVPCをどうするかといったことをあまり考えずに行いたいので、上3つは候補から外します。 次にGlueのPython Shellは最小課金が1分に切り上げとなるので、Lambdaで実装する想定だった処理に用いてしまうと料金が跳ねてしまう恐れがあります。
ここらへんを考えるとre:invent 2020で発表があったLambdaのコンテナイメージサポートを用いての実装が良さそうな気がします。
実際に構築してみる
Lambdaのコンテナサポートですが、用いるためには以下を行う必要があります。
- Dockerイメージを作成
- ECRのレジストリの作成
- ECRにPush
- Lambda関数の定義
さっと考えるだけでも意外と煩雑な作業が必要になります。 これを楽に行いたいので、フレームワークの恩恵を受けましょう。
SAM CLIやServerless Frameworkはここらへんのサポートがあるので、上記のような煩雑な作業を行うことなくコンテナイメージで動くLambdaを用意にデプロイすることが可能です。
Deployしてみた
自分が実際にDeployした環境は以下のとおりです。
- macOS Catalina
- Docker desktop 3.1.0(51484)
- Node.js v14.5.0
実際にデプロイしたServerless Frameworkのアプリケーションは以下のリポジトリに格納してあります。
CM-Kajiwara/connect-snowflake-with-pandas-use-serverless-framework
リポジトリ内の要点を解説していきます
dockerフォルダ配下
ここのディレクトリの内容をもとにコンテナイメージを作成していきます。 フォルダ名はserverless.ymlで指定しているので、任意の名前に変更可能です。
docker/Dockerfile
このファイルでLambdaに構築するコンテナイメージを定義しています。
RUN python3.8 -m pip install "snowflake-connector-python[pandas]" -t .
snowflake-connector-pythonでpandasを組み込ませるときの指定は上記のように行う必要があります。
PythonコネクタでのPandas DataFrames の使用 — Snowflake Documentation
docker/access_sample.py
def handler(event, context)
Lambdaから呼び出す際のエントリーポイントとなる関数を実装しておく必要があります。 中身の実装に関してはSnowflakeに対してクエリを投げて、クエリの結果をPandasで集計しているといった内容になります。
PythonコネクタでのPandas DataFrames の使用 — Snowflake Documentation
serverless.yml
Serverless Frameworkの定義になります。 Lambdaのコンテナサポートを使うための設定についていくつか解説します。
ecr: images: baseimage: path: ./docker file: Dockerfile
どこに記載されているDockerファイルをECRに登録するかの定義になります。 ここに記載されているDockerfileを元にコンテナを作成し、ECRに登録まで行います。
functions: hello: image: baseimage
ここでLambda Functionsを定義するのですが、今回はコンテナサポートのLambdaのため記載は上記で定義したDockerのイメージ名を記載するのみとなっています。
実際に動かしてみた
MFAを使っている環境でServerless FrameworkのDeployを行うとDeploy中の表示がうまく行かないことがあるので、 自分は以下のようなシェルからデプロイをするようにしています。
Profile="insert your profile" export AWS_PAGER="" role_arn=`aws configure get role_arn --profile ${Profile}` sts_result=`aws --profile ${Profile} sts assume-role --role-arn ${role_arn} --role-session-name deploy --duration-seconds 900` export AWS_ACCESS_KEY_ID=`echo ${sts_result} | jq -r '.Credentials.AccessKeyId'` export AWS_SECRET_ACCESS_KEY=`echo ${sts_result} | jq -r '.Credentials.SecretAccessKey'` export AWS_SESSION_TOKEN=`echo ${sts_result} | jq -r '.Credentials.SessionToken'` export AWS_SDK_LOAD_CONFIG=true export AWS_DEFAULT_REGION=ap-northeast-1 serverless deploy --debug --verbose
上記のシェルを実行し、DeployされたLambdaを動かした結果が以下となります。
OpenBLAS WARNING - could not determine the L2 cache size on this system, assuming 256k START RequestId: 2aeb4930-0927-41b5-9072-047d6de5d1b0 Version: $LATEST 売上 都道府県 三重県 35893.000000 兵庫県 11440.666667 北海道 12611.400000 千葉県 19311.000000 和歌山県 22002.000000 埼玉県 37980.800000 大分県 21052.000000 大阪府 30318.000000 山口県 13730.000000 山形県 13032.000000 岡山県 30233.125000 岩手県 20717.000000 広島県 3365.000000 愛媛県 38128.000000 愛知県 53768.250000 新潟県 28496.000000 東京都 15388.500000 沖縄県 18220.000000 滋賀県 19680.000000 石川県 13559.000000 神奈川県 171390.000000 福岡県 18822.666667 静岡県 9301.875000 END RequestId: 2aeb4930-0927-41b5-9072-047d6de5d1b0 REPORT RequestId: 2aeb4930-0927-41b5-9072-047d6de5d1b0 Duration: 2286.65 ms Billed Duration: 5140 ms Memory Size: 512 MB Max Memory Used: 182 MB Init Duration: 2852.78 ms
Snowflakeからクエリでとってきた結果に対して、Pandasで集計をしているのがわかります。
まとめ
Snowflakeというより、Lambdaのコンテナサポートのデプロイ方法の紹介でしたが、 Snowflake以外においてもLambda Layerの上限に達しそうなときに取れる選択肢にはなるかと思います。 Serverless Frameworkのサポートも思った以上に手厚かったので、Lambdaを活用するときの選択肢の一つになりそうです。