Lambda上でsnowflake-connector-pythonとPandasを用いてデータ取得を行ってみた

2021.02.12

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

好物はインフラとフロントエンドのかじわらゆたかです。 同僚から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のコンテナサポートですが、用いるためには以下を行う必要があります。

  1. Dockerイメージを作成
  2. ECRのレジストリの作成
  3. ECRにPush
  4. 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のイメージ名を記載するのみとなっています。

https://www.serverless.com/framework/docs/providers/aws/guide/functions#referencing-container-image-as-a-target

実際に動かしてみた

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を活用するときの選択肢の一つになりそうです。