Lambda Layers
AWS Lambdaのデプロイパッケージには50MBのサイズ制限がある。Numpy・SciPy・OpenCVをベタにビルドすると、それだけでお腹いっぱい。
そこでLambda Layers。展開後のサイズで250MBまで使える。
AWS公式は現在Numpy・SciPyのみ提供している。OpenCVも当然あっていいはずなのに今はまだないので、丸1日かけてビルドした。
追記
展開後250MB制限がつらいので、節約術(strip -s)を使った。70MBほど減っている。
準備
要Docker。
使うOpenCVのバージョンを決める。決めたら、ソースツリーをzipで固める。ファイル名はopencv-master.zipとopencv_contrib-master.zip。もしHEADでよければ、GitHubでDownload ZIPしたそのまんま。
ビルド
以下のDockerfileとdocker-compose.ymlと同じところに、opencv-master.zipとopencv_contrib-master.zipを置いておく。
FROM lambci/lambda:build-python3.6
ENV AWS_DEFAULT_REGION ap-northeast-1
ENV HOME /home/hoge
RUN mkdir $HOME
WORKDIR $HOME
COPY opencv-master.zip .
RUN unzip opencv-master.zip
RUN mv opencv-master opencv
COPY opencv_contrib-master.zip .
RUN unzip opencv_contrib-master.zip
RUN mv opencv_contrib-master opencv_contrib
RUN yum update -y
RUN sed -i -e 's/enabled=0/enabled=1/' /etc/yum.repos.d/epel.repo
RUN yum install cmake3 -y
RUN pip install --upgrade pip
RUN pip install numpy
RUN mkdir ~/opencv/build
WORKDIR $HOME/opencv/build
RUN cmake3 -D CMAKE_BUILD_TYPE=RELEASE -D BUILD_SHARED_LIBS=NO \
-D BUILD_LIST=aruco,features2d,imgcodecs,imgproc,python3,xfeatures2d \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
-D PYTHON3_EXECUTABLE=/var/lang/bin/python \
-D CMAKE_INSTALL_PREFIX=~/bar_dist ..
RUN make install
RUN mkdir -p ~/foo/python
RUN mv ~/bar_dist/lib ~/foo/python/
WORKDIR $HOME/foo
RUN find . -name *.so|xargs -n 1 strip -s
CMD zip -ry9 ~/cv2_layer.zip * && cp ~/cv2_layer.zip /share
version: '2'
services:
app:
build:
context: .
volumes:
- .:/share
上記のDockerfileなどなどを置いたディレクトリで、
docker-compose build
docker-compose up
カレントディレクトリにcv2_ll.zipが生成される。
使い方
cv2_ll.zipをAWSコンソールでLayerとして登録する。自分のLambda FunctionにこのLayerをつける。このとき、AWS公式で提供されているNumpy・SciPyのLayerも同時につける必要がある。
importに時間がかかるので、ハンドラモジュールのグローバルでimportする必要がある。ハンドラ関数内でimport cv2しようとすると、デフォルトの制限時間の3秒以内に終わらない。
OpenCVモジュールの取捨選択
BUILD_LISTを編集する。ちなみに上のリストでビルドすると、2019/01/08のHEADで展開後サイズが49,254,022バイトとなる。
共有ライブラリ?
上の例では静的リンクしてあるので、メモリを余計に食っているはず。Lambda FunctionでLD_LIBRARY_PATHを見ると/opt/libに通っているので(Layerは/optに展開される仕組み)、もしここに.soを配置すれば使えるはず。
追記:
むしろメモリを余計に食った。import cv2しただけの状態で54MB vs 58MB。
参考
AWS Lambda で OpenCV と Pillow を使う環境を準備する
Using Packages and Native nodejs Modules in AWS Lambda