こんにちは、エンジニアの君島です。
AWS CloudShell便利ですよね。私はCLIを使う時には、ローカルよりもよく使っていると思います。
Lambda開発まわりでも使うことがあったので、試行錯誤した過程も含めて紹介します。
目次
はじめに
2023年11月現在、AWS LambdaにおけるPythonの最新ランタイムは3.11になります。
Pyhon3.11でコードを書いていたところ、OpenCV-pythonが必要になったので、AWS CloudShellを使いながらLambda Layerを作ってみました。
いくつかのつまづきポイントがあったので、それも踏まえて手順を紹介していきます。
AWS CloudshellでPython3.11互換のopencv-pythonのLambda Layerを作る
AWS CloudShellにPython3.11をインストールする
CloudShellのOSや入っているPythonのバージョンを確認
2023年11月現在では、AWS CloudShellのOSはAmazon Linux2でデフォルトでPython3.7が入っています。
また、Extras LibraryではPython3.8まで上げることができるようです。
ただ、今回はPython3.11を使用したいので、手動で入れていきましょう。
AWS CloudShellにpyenvを使ってPython3.11.6をインストールする
pyenvというPython用のバージョン管理ツールを利用していきましょう。
1 2 3 4 5 6 7 8 |
sudo yum install -y openssl11 openssl11-devel sudo yum install -y gcc make zlib-devel bzip2 bzip2-devel readline-devel sqlite-devel tk-devel libffi-devel xz-devel git clone https://github.com/pyenv/pyenv.git ~/.pyenv echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc echo 'command -v pyenv >/dev/null || export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc echo 'eval "$(pyenv init -)"' >> ~/.bashrc source ~/.bashrc pyenv install 3.11.6 |
ビルドとインストールが無事に完了したら、バージョンを切り替えて確認してみましょう。
pyenvは、CloudShellの永続的ストレージ上にgit cloneしているので、セッションが切れてもまた利用することができます。
1 2 |
pyenv global 3.11.6 python -V |
つまづきポイント① opensslのバージョン要件
なお、Python3.10からOpenSSL1.1.1以上が要件となっています。
Amazon Linux2でバージョン指定せずにOpenSSLをインストールすると、バージョンは1.0.2kになってしまうため、この要件に満たしません。
そのため、このままビルドしてもModuleNotFoundErrorとなってしまいます。
OpenCV-pythonのLambdaレイヤーを作成する
Layer保存用のs3バケットを作成する
1 |
aws s3 mb s3://<BUCKET_NAME> |
OpenCV-pythonをインストールする
1 2 |
mkdir python pip install -t python/ opencv-python |
requirements.txtを用意するやり方もありますが、スモールなLayerなので直接コマンドでインストールするモジュールを指定しました。
mesa-libGLのインストールと共有ライブラリの配置
opencv-pythonのLambda Layerを作る場合には必要な手順になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sudo yum install -y mesa-libGL cp /usr/lib64/libGL.so.1 ./python/opencv_python.libs/ cp /usr/lib64/libGLX.so.0 ./python/opencv_python.libs/ cp /usr/lib64/libX11.so.6 ./python/opencv_python.libs/ cp /usr/lib64/libXext.so.6 ./python/opencv_python.libs/ cp /usr/lib64/libGLdispatch.so.0 ./python/opencv_python.libs/ cp /usr/lib64/libdl.so.2 ./python/opencv_python.libs/ cp /usr/lib64/libpthread.so.0 ./python/opencv_python.libs/ cp /usr/lib64/libc.so.6 ./python/opencv_python.libs/ cp /usr/lib64/libxcb.so.1 ./python/opencv_python.libs/ cp /usr/lib64/libXau.so.6 ./python/opencv_python.libs/ cp /usr/lib64/libgthread-2.0.so.0 ./python/opencv_python.libs/ cp /usr/lib64/libglib-2.0.so.0 ./python/opencv_python.libs/ |
Lambda Layerを作成して登録する
1 2 3 |
zip -rq layer.zip python/ aws s3 cp layer.zip s3://<BUCKET_NAME>/layer/layer.zip aws lambda publish-layer-version --layer-name opencv-python-3-11 --compatible-runtimes python3.11 --content S3Bucket=<BUCKET_NAME>,S3Key=layer/layer.zip |
このような出力になればLayerとして登録されています。
つまづきポイント② mesa-libGLの共有ライブラリ不足
mesa-libGLの作業を飛ばして、単にopencv-pythonだけを含むLayerを登録したLambdaを実行するとResponseは以下のようになってしまいます。
1 2 |
"errorMessage": "Unable to import module 'lambda_function': libGL.so.1: cannot open shared object file: No such file or directory", "errorType": "Runtime.ImportModuleError", |
これは、libGL.so.1がLayerやLambdaの実行環境に存在しないからなので、Layerに含めてしまいましょう。
ただし、単に該当する共有ライブラリをいれるだけではなく、依存しているライブラリも同梱する必要があります。そこでlibGL.so.1の依存関係も調べてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 |
[cloudshell-user@ip-10-6-70-28 ~]$ ldd /usr/lib64/libGL.so.1 linux-vdso.so.1 (0x00007fff24b91000) libGLX.so.0 => /lib64/libGLX.so.0 (0x00007f5970797000) libX11.so.6 => /lib64/libX11.so.6 (0x00007f597045f000) libXext.so.6 => /lib64/libXext.so.6 (0x00007f597024d000) libGLdispatch.so.0 => /lib64/libGLdispatch.so.0 (0x00007f596ff97000) libdl.so.2 => /lib64/libdl.so.2 (0x00007f596fd93000) libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f596fb75000) libc.so.6 => /lib64/libc.so.6 (0x00007f596f7c8000) libxcb.so.1 => /lib64/libxcb.so.1 (0x00007f596f5a0000) /lib64/ld-linux-x86-64.so.2 (0x00007f5970c55000) libXau.so.6 => /lib64/libXau.so.6 (0x00007f596f39c000) |
ただ、実際には上記のものだけでは足りなくて、libGL.so.1以外にもlibgthread-2.0.so.0とlibglib-2.0.so.0でもModuleNotFoundErrorが出てしまいました。
同じようにLayerに含めてあげる必要がありました。
AWS Lambdaにレイヤーを設定して実行してみる
実行する関数の用意
ランタイムを最新のPython3.11にした関数を用意します。
コードには、opencv-pythonをインポートした簡単な実装を施します。
1 2 3 4 5 6 7 8 9 10 11 |
import json import cv2 def lambda_handler(event, context): print(cv2.__version__) return { 'statusCode': 200, 'body': json.dumps('Hello from Lambda!') } |
この状態で関数を実行してもモジュールが見つかりません、というエラーになってしまいます。
レイヤーの設定
それでは、これまでに作成したレイヤーを関数に設定しましょう。
AWS Lambdaのコンソールからレイヤーとバージョンを指定してあげます。
その上で、関数を実行すれば、正常に終了して、ログにopencvのバージョン情報も記載されているのが分かります。
まとめ
AWS CloudShellでPython3.11互換のopencv-pythonのLambda Layerを作ってみました。
いくつかのつまづきポイントがありましたが、それらを乗り越えていく過程もご紹介しました。
念のため、Layer作成後のAWS CloudShellのストレージ状況を見ると80%強の使用状況で、まだ余裕がありました。
一方で、Layerの展開後のサイズはほぼ250MBなので、そちらの方がAWS Lambdaのクオータに引っかかる寸前でした。
なお、展開後のサイズが250MB以上の場合は、Layerを作成する際に以下のようなエラーとなってしまいます。
告知
カジュアル面談も実施中
ギークフィードではAWSエンジニアなどの職種で一緒に働く仲間を募集しています。
弊社に興味を持っていただいたり、会社のことをカジュアルに聞いてみたいという場合でも、ご気軽にフォームからお問い合わせください。その場合はコメント欄に、カジュアルにお話したいです、と記載ください!
2023 Advent Calendar開催します
ギークフィードでは今年もアドベントカレンダーを開催、及び参加します。
開催、あるいは社員が参加することが決まっているアドベントカレンダーを以下に列挙しておきます。
ギークフィード主催のアドベントカレンダーです。スカイアーチHRソリューションズさんもご参加いただきます。
Amazon Connect Advent Calendar 2023
Amazon Connectにフォーカスしたアドベントカレンダーです。昨年に引き続きクラスメソッドさんと共催です。スカイアーチHRソリューションズさんもご参加いただきます。
Japan AWS Ambassadors Advent Calendar 2023
Japan AWS Ambassadorsによるアドベントカレンダーです。
Japan AWS Jr. Champions Advent Calendar 2023
Japan AWS Jr.Championsによるアドベントカレンダーです。
- CLIでAmazon S3にあるファイル内の文字列検索をしてみる - 2024-02-01
- 不完全なマルチパートアップロードをCLIで確認してS3の無駄コストを無くそう - 2024-01-29
- AlmaLinux9.3にPHP8.3を入れてLaravel9から10にバージョンアップする - 2024-01-12
- AWS CloudShellの表現力を確認してみよう - 2024-01-01
- AWSのアーキテクチャーを学べるAWS Card Clash攻略Wiki - 2023-12-26