4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

OpenCVをAWS Lambda + Python + Serverless Frameworkで動かす

Posted at

OpenCVをAWS Lambda + Python + Serverless Frameworkで動かしてみました。

先日、PillowをLambdaで動かす記事を書きましたが、このときと違って、OpenCVはyumでインストールの必要なshared objectに依存しているのでだいぶ面倒でした。

手順概要

  1. serverless-python-requirements インストール
  2. Pythonサンプルコードを記述
  3. requirements.txt と serverless.yml と Dockerfile にOpenCV動作に必要な事項を記述
  4. あとはデプロイ

OpenCV特有は3のみです。

手順詳細

serverless-python-requirements インストール

AWS Lambda + Python + Serverless FrameworkにPythonのパッケージをインストールする方法は以前の記事に書きました。

これに従って、まずは serverless create して、serverless-python-requirementsプラグインをインストールします。

$ serverless create --template aws-python3

$ serverless plugin install -n serverless-python-requirements

ServerlessFrameworkのバージョンはv2.18.0でした。

Pythonソースコード

handler.py の内容です。OpenCVを参照できることを確認できる最小限です。

import cv2

def hello(event, context):
    print("Hellow, OpenCV!")
    print(cv2.__version__)

requirements.txt

OpenCVのパッケージ名を記述します。この1行のみです。

opencv-python

serverless.yml

serverless.yml の記載がもっとも面倒でした。成功例を書きます。

service: sample

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: ap-northeast-1

functions:
  hello:
    handler: handler.hello
    events:
      - httpApi: "*"

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    dockerizePip: true
    dockerFile: Dockerfile
    dockerExtraFiles:
      - /usr/lib64/libGL.so.1
      - /usr/lib64/libgthread-2.0.so.0
      - /usr/lib64/libglib-2.0.so.0
      - /usr/lib64/libGLX.so.0
      - /usr/lib64/libX11.so.6
      - /usr/lib64/libXext.so.6
      - /usr/lib64/libGLdispatch.so.0
      - /usr/lib64/libxcb.so.1
      - /usr/lib64/libXau.so.6

Dockerfile

Dockerfile を作成します。serverless.ymlからファイル名で参照しています。

FROM lambci/lambda:build-python3.8

RUN yum install -y mesa-libGL

デプロイと実行

デプロイ。

$ serverless deploy -v

デプロイされたLambdaを実行するとCloudWatch Logsに以下が出力されました。

Hellow, OpenCV!
4.5.1

serverless.yml を書くまでの道のり

最初は以下だけで動かそうとしました。

service: sample

frameworkVersion: '2'

provider:
  name: aws
  runtime: python3.8
  lambdaHashingVersion: 20201221
  region: ap-northeast-1

functions:
  hello:
    handler: handler.hello

plugins:
  - serverless-python-requirements

これでデプロイしてLambdaを実行すると、CloudWatch Logsに以下のエラーが吐かれました。

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

libGL.so.1 というファイルが不足しているので、これを追加すればよいのですが、これは環境に依存していそうなので、手元にある同じファイル名をコピーしただけではたぶん動きません。Lambdaの動くAmazon Linux環境でこのファイルを用意する必要があります。

これをするためにserverless.yml にdockerの記述をします。以下の記述です。

custom:
  pythonRequirements:
    dockerizePip: true
    dockerFile: Dockerfile
    dockerExtraFiles:
      - ...

Dockerfileも用意します。

FROM lambci/lambda:build-python3.8

RUN yum install -y mesa-libGL # OpenCVに必要なパッケージをインストール

これを書くだけでserverlessがデプロイ時にDockerを起動して、Lambdaの動くAmazon Linux環境を再現し、その中でyumインストールしてくれます。serverless.ymldockerExtraFilesに記載したファイルを、yumインストール後に抜き出して、Lambdaデプロイイメージに同梱してくれます。

dockerExtraFilesに書いたリストは、デプロイして実行時のエラーメッセージから1つずつ書き足して、成功するまで繰り返しました。

エラーメッセージにはsoファイル名しか表示されませんので、以下のコマンドでLambdaの動くAmazon Linux環境の中に入ってみて、yum install -y mesa-libGLしてから、soファイルのありかを探しました。

$ docker run -it --rm lambci/lambda:build-python3.8 bash

Amazon Linux上では /usr/lib64/libGL.so.1/usr/lib64/libGL.so.1.7.0 へというように、すべてシンボリックリンクになっていますが、serverless.ymlには実態ではなくシンボリックリンクだけ記述すれば動きました。

注意事項

ここに書いているsoファイルのリストはサンプルPythonコードを動かすために最小限のものです。エラーメッセージを見て、足りないsoファイルを追加するというのを繰り返しましたのみです。従ってOpenCVのすべての動作がこれだけで足りてるかどうかはわかりません。

ハマりどころ1

.serverless/requirements/の中にLambdaのイメージが展開されるのですが、Dockerで構築されるためか、soファイルがroot権限になり、試行錯誤の過程で serverless.yml の変更が権限不足で反映できないというトラブルがありました。原因がわかればroot権限でそのディレクトリを削除することで解決しましたが、それに気が付くまで時間をだいぶ消耗しました。

ハマりどころ2

serverlessが内部でDockerを利用するため、serverless自体をDockerの中で動かしたらデプロイ時にDockerでエラーになりました。Dockerのvolumeも使っていたので、Dockerのsocket共有でもうまくいかず、あきらめました。

ハマりどころ3

最初はLambdaのLayerにOpenCVを入れたかったのですが、LD_LIBRARY_PATH がLayerには通っていないため、OpenCVを動作させることはできませんでした。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?