localstackを使ったlambdaのdeployについて
初めに
localstackにpython lambdaのdeployを試みた。
いろいろと詰まる部分があったので整理しておきます。
結論
- lambda layer は proである必要がある(https://docs.localstack.cloud/user-guide/aws/lambda/#lambda-layers-pro)
- インストールしたパッケージをhandlerのコードと同じディレクトリに直置きすればlayerを使わずに済む
- pythonの依存関係をインストールする場合は実行時のインタープリタのバージョンと合わせたpipを使うこと
localstackのlambda layer
以下の様なコマンドでlayerのpublishができる
mkdir python
pip install -r requirements.txt -t python
zip -r my-layer.zip python
awslocal lambda publish-layer-version \
--layer-name my-layer \
--zip-file fileb://my-layer.zip
以下の様なコマンドでlayerを使うlambdaがdeployできる
zip -r /tmp/func.zip ./src/*
function_name=my-func
role=arn:aws:iam::000000000000:role/lambda-role
awslocal lambda create-function \
--function-name ${function_name} \
--runtime python3.9 \
--handler index.handler \
--zip-file fileb:///tmp/func.zip \
--role ${role} \
--architectures arm64 \
--layers arn:aws:lambda:ap-northeast-1:000000000000:layer:my-layer:1
しかし実際にlambdaのコンテナにはいってpythonを実行するとrequirements.txtでインストールしたはずのパッケージがないというエラーが起きる。
deployの時点では成功するのが罠。
localstack proでないとlayerがつかえない。
layerを使わずにパッケージ込みのlambdaをdeployする
ではどうするかというと、lambdaのhandlerのコードと同じところにパッケージを展開してやり、zip化してやればよい。
具体的には以下の様なコードでdeployする。
mkdir /tmp/lambda_src
pip install -r requirements.txt -t /tmp/lambda_src
(cp ./src/* /tmp/lambda_src && cd /tmp/lambda_src && zip -r /tmp/func.zip ./*)
function_name=my-func
role=arn:aws:iam::000000000000:role/lambda-role
awslocal lambda create-function \
--function-name ${function_name} \
--runtime python3.9 \
--handler index.handler \
--zip-file fileb:///tmp/func.zip \
--role ${role} \
--architectures arm64 \
--layers arn:aws:lambda:ap-northeast-1:000000000000:layer:my-layer:1
pip install -t でインストール先のディレクトリを指定。
(実際にはpipだけではダメな場合あり。次に説明)
cp でhandlerのコードを同じディレクトリにコピー。
同じディレクトリに移動してzipファイル作成。
依存関係インストール時のpythonのインタプリタのバージョンを合わせる
前述の通りに実施しても、
"ModuleNotFoundError: No module named 'psycopg2._psycopg'"
という様なエラーが出ることがある。これはpythonのバージョンの差異による問題。
例えば、python3.9のlambdaの実行環境に対してpython3.10でpip installしてパッケージを準備すると、psycopg2/_psycopg のファイルが存在せず、import時にエラーとなる。これを回避するためには
python3.9 -m pip install ...
の様にpython3のバージョンを指定してpipを実行すればよい。
最後に
awslocal lambda create-function の処理が通ってしまったので、layerが使えるはずだと勘違いしてだいぶ時間を食ってしまいました。awslocalで新しいコマンドを実行する時は、community対応しているかどうかを最初に確認する必要がありますね。
Discussion