Lambda レイヤーにライブラリを追加する ( OpenCV 編)

概要

Lambda の Python ランタイムから OpenCV モジュールを利用できるようにするため、Lambda レイヤーに OpenCV を追加します。

構築環境

Copied!
$ python -V
Python 3.9.12
$ pip -V
pip 22.0.4 from /home/ec2-user/.anyenv/envs/pyenv/versions/3.9.12/lib/python3.9/site-packages/pip (python 3.9)

Lambda レイヤーに OpenCV モジュールを追加する手順

作業用ディレクトリとレイヤーパスの作成

Copied!
mkdir -p ~/opencv_layer/python

OpenCV  (opencv-python) のインストール

python ディレクトリに opencv-python をインストールします。

Copied!
$ cd ~/opencv_layer
$ pip install opencv-python -t python
Collecting opencv-python
  Using cached opencv_python-4.5.5.64-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (60.5 MB)
Collecting numpy>=1.17.3
  Using cached numpy-1.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (16.8 MB)
Installing collected packages: numpy, opencv-python
Successfully installed numpy-1.22.3 opencv-python-4.5.5.64

mesa-libGL のインストール

現状、opencv-python をインストールしたディレクトリをプロイパッケージ化 (zip ファイルアーカイブ) して、Lambda レイヤーを作成して cv2import すると以下のようなエラーが発生します。

Copied!
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': libGL.so.1: cannot open shared object file: No such file or directory

既知の問題みたいで以下のサイトを参考に対応していきます。

まず、mesa-libGL をインストールします。

Copied!
sudo yum install -y mesa-libGL

mesa-libGL をインストール後に、必要なライブラリを python ディレクトリに追加します。

Copied!
cd ~/opencv_layer
cp -v /usr/lib64/libGL.so.1 ./python/opencv_python.libs/
cp -v /usr/lib64/libgthread-2.0.so.0 ./python/opencv_python.libs/
cp -v /usr/lib64/libglib-2.0.so.0 ./python/opencv_python.libs/
cp -v /usr/lib64/libGLX.so.0 ./python/opencv_python.libs/
cp -v /usr/lib64/libX11.so.6 ./python/opencv_python.libs/
cp -v /usr/lib64/libXext.so.6 ./python/opencv_python.libs/
cp -v /usr/lib64/libGLdispatch.so.0 ./python/opencv_python.libs/
cp -v /usr/lib64/libGLX_mesa.so.0.0.0 ./python/opencv_python.libs/
cp -v /usr/lib64/libxcb.so.1 ./python/opencv_python.libs/
cp -v /usr/lib64/libXau.so.6 ./python/opencv_python.libs/
cp -v /lib64/libGLdispatch.so.0.0.0 ./python/opencv_python.libs/

軽量化のために不要なファイルを削除する

そのままだと、236 MB もあるので不要なファイルを削除して少しでも軽くします。

Copied!
$ du -sh python/
236M    python/

Serverless Framework の [Slim Package]1 を参考に dist-info__pycache__pycpyo を削除します。

Copied!
find ./python -type d -regextype posix-basic -regex ".*dist-info.*" | xargs rm -rf
find ./python -type d -regextype posix-basic -regex ".*__pycache__.*" | xargs rm -rf
find ./python -type f -regextype posix-basic -regex ".*\.py[c|o]" | xargs rm -rf

8 MB だけ軽くなりました。。。

Copied!
$ du -sh python/
228M    python/

軽量化とは別ですが、オブジェクトファイルからのシンボルテーブルなどを削除する strip コマンドを実行したデプロイパッケージを使用すると以下のようなエラーが発生しますので、やらないようにしましょう。

Copied!
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': /opt/python/cv2/cv2.abi3.so: ELF load command address/offset not properly aligned

デプロイパッケージ化 (zip ファイルアーカイブ)

Copied!
cd ~/opencv_layer
zip -r9 opencv_layer.zip python

不要なファイルを削除して軽量化する

Lambda レイヤーの作成

デプロイパッケージを使用した Lambda レイヤーの作成手順はこちらにまとめてあります。

動作確認

作成した Lambda レイヤーを使用する Lambda 関数を作成し、テスト実行してみます。
特にエラーが発生せず、実行結果のログに cv2 モジュール内で定義されている関数、属性などの一覧が表示されていれば成功です。

Copied!
import cv2

def lambda_handler(event, context):
        print(dir(cv2))

Lambda レイヤーに ライブラリを追加する ( OpenCV 編) まとめ

opencv-python をインストールしただけでも 236 MB にもなります。
2022/04 時点では、Lambda デプロイパッケージ (zip ファイルアーカイブ) の上限サイズは 250 MB (解凍後)2 です。
かなりギリギリで、opencv-python 以外のモジュールを追加するのも難しいです。
opencv-contrib-python なんて入りません。
どうしても Lambda で opencv を使用する場合は、コードパッケージサイズの上限が 10 GB2 もあるコンテナイメージを使用することを検討した方良いかなと思います。

Footnotes

  1. Serverless Framework: Plugins

  2. Lambda クォータ - AWS Lambda 2