🎃

AWS Lambdaでpython-snowflake-connectorを使う

2024/04/30に公開

前置き

こんにちは。さすらいのデータエンジニアのこみぃです。

AWS Lambdaでpython-snowflake-connectorを使いたいこと、ありますよね。

先日それをやろうとしてちょっと苦戦したので本日はそんなお話です。

Layerを使う

AWS Lambdaでライブラリを使いたい場合には、デフォルトで組み込まれているライブラリ以外はLayerというものを作って関数にセットする必要があります。

python-snowflake-connectorは残念ながらデフォルトには入っていないので、Layerを使う必要があります。

実はLayerは有志で作成して公開されているものがあります。みんなが使うようなLayerは置いてあります。
https://github.com/keithrozario/Klayers

なのでそこにあれば楽なのですが、python-snowflake-connectorは残念ながら存在しませんので自分で作る必要があります。

Layerを作る

さて、Layerはpip installを-tオプションでディレクトリ指定で行って、作られたディレクトリをzip圧縮することで作ることができるのですが、ここが最大のハマりポイント。

何も考えずにMac or Windowsで作ると以下のようなエラーに悩まされることになります。

error
Unable to import module 'lambda_function': /opt/python/cryptography/hazmat/bindings/_rust.abi3.so: cannot open shared object file: No such file or directory

これはなぜ起こるかというと、Layerを作った環境とLambdaが実行される環境で違いがあるからです。Lambdaが実行されるのはAmazonlinux2なので、その環境でLayerを作らなければなりません。

EC2にAmazonlinux2を立てるという作戦もありますが、こんなときこそコンテナ技術の出番です。そう、Dockerだね!!

ここからは先駆者様の以下の記事を参考に作ります。
https://qiita.com/hoto17296/items/a374efc2d8159d75bc71

DockerDesktopをインストールした後、適当にディレクトリを切って、2つのファイルを作ります。

Dockerfile
FROM amazonlinux:2

ARG PYTHON_VERSION=3.12.1

RUN yum update -y && yum install -y tar gzip make gcc openssl11 openssl11-devel bzip2-devel libffi-devel \
  && curl https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz | tar xz \
  && cd Python-${PYTHON_VERSION} && ./configure && make && make install \
  && cd - && rm -rf Python-${PYTHON_VERSION}

ADD entrypoint.sh /

RUN yum install -y zip \
  && mkdir /python \
  && chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
entrypoint.sh
#!/bin/bash -eu

SRC=/python
DIST=/dist/layer.zip

pip3 install -t ${SRC} $@
rm -f ${DIST}
zip -q -r ${DIST} ${SRC}

元記事様のものからDockerfileをいじっていて、opensslではなくopenssl11にしています。合わせてrequestsを使いたいことが多かったのですが、openssl11じゃないとうまく動かなかったのでこうしています。

ここまでできたらdockerをbuild

docker build
docker build . -t python_layer_build_312 --platform linux/x86_64 --no-cache

ここで注意が必要なのが、platformを指定する必要があることです。Lambdaのデフォルトがx86_64なのでここではそちらを指定しています。ここが多分エラーの根本的な原因です。

後はdockerをrunしてsnowflake-python-connectorのLayerを作ります

docker run
docker run --rm -v ./:/dist python_layer_build_312 snowflake-connector-python

うまくいったらカレントディレクトリにlayer.zipというファイルが作られています。

ls
$ ls
Dockerfile	entrypoint.sh	layer.zip

こうしてできたlayer.zipが求めていたLayerのファイルになります。

Lambdaにセット

ここまでできたらLambdaのLayerを作成しましょう。

Lambdaの左メニューからLayerを選んで新規作成ボタンを押して、こんな感じで追加します。

続いてLambdaの編集画面の一番下でカスタムレイヤーを追加すればOK

Lambdaを実行してみる

最後に、ちゃんとimportできるか試してみましょう。

test_lambda
import json
import requests
import snowflake.connector

def lambda_handler(event, context):
    # TODO implement
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

ね。簡単でしょ?

結びの言葉

今だと他に定期処理をするためのいろいろな方法がありますので、そもそもLambdaでやらないほうがいい可能性はあるのですが、使いたい人はいそうですよね。そんな方の助けになりましたら幸いです。
そんなわけで、案外とどこにも記事が見つからなかったので、記事にしてみました。記事がなかったら自分で記事を書く、エンジニアの鑑。

最後に一つ宣伝を。
GENDAデータチームではプロダクトのデータ解析や機械学習プロジェクトを推進できるデータサイエンティストを募集しています。
https://open.talentio.com/r/1/c/genda/homes/4356

興味がおありの方は、ぜひぜひご連絡ください。
また、データサイエンティスト以外でも、なんならデータ系以外の方でも、優秀な方を常に求めています。GENDAという会社に興味があれば、是非お声おかけください。

本日はこのあたりで。
それじゃあ、バイバイ!

Discussion