Lambdaのコンテナイメージサポートを利用してPython + OpenCV環境を作る

はじめに

これまでAWS LambdaでPythonからOpenCVを利用するには環境構築に少しばかり手間がかかりました。

素直にpipでopencv-pythonをインストールするだけではLambdaの実行環境に必要なバイナリが存在せずエラーとなり、またファイルサイズが大きいためにLayerに切り出したりする工夫が必要でした。

今回はLambdaのContainer Image Supportによってその辺りの工夫が不要になり、簡単にPython + OpenCV環境を作ることができるようになったため備忘録として残しておきます。

AWS Lambda Container Image Support

2020/12にLambda関数をコンテナイメージとしてパッケージ化しデプロイできるようになるリリースがありました。イメージサイズの上限が10GBまでと大きいため、OpenCVや機械学習系のサイズが大きくなりがちなライブラリも気にせず利用できるようになっています。

AWS Lambda の新機能 – コンテナイメージのサポート

やってみる

SAM CLIでアプリケーションを作成する際、package typeでImageを選択します。

(SAMでなくてもContainer Supportは利用できますが、今回は使い慣れているSAMでプロジェクトを作ります。)

$ sam init
Which template source would you like to use?
	1 - AWS Quick Start Templates
	2 - Custom Template Location
Choice: 1
What package type would you like to use?
	1 - Zip (artifact is a zip uploaded to S3)
	2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2

Which base image would you like to use?
	1 - amazon/nodejs14.x-base
	2 - amazon/nodejs12.x-base
	3 - amazon/nodejs10.x-base
	4 - amazon/python3.8-base
	5 - amazon/python3.7-base
	6 - amazon/python3.6-base
	7 - amazon/python2.7-base
	8 - amazon/ruby2.7-base
	9 - amazon/ruby2.5-base
	10 - amazon/go1.x-base
	11 - amazon/java11-base
	12 - amazon/java8.al2-base
	13 - amazon/java8-base
	14 - amazon/dotnet5.0-base
	15 - amazon/dotnetcore3.1-base
	16 - amazon/dotnetcore2.1-base
Base image: 4

Project name [sam-app]: sam-opencv-app

Cloning app templates from https://github.com/aws/aws-sam-cli-app-templates

AWS quick start application templates:
	1 - Hello World Lambda Image Example
	2 - PyTorch Machine Learning Inference API
	3 - Scikit-learn Machine Learning Inference API
	4 - Tensorflow Machine Learning Inference API
	5 - XGBoost Machine Learning Inference API
Template selection: 1

   -----------------------
   Generating application:
   -----------------------
   Name: sam-opencv-app
   Base Image: amazon/python3.8-base
   Dependency Manager: pip
   Output Directory: .

   Next steps can be found in the README file at ./sam-opencv-app/README.md


requirements.txtにopencv-pythonを追加し、

opencv-python


Dockerfileで必要な依存をインストールするよう記述します。

FROM public.ecr.aws/lambda/python:3.8

COPY app.py requirements.txt ./

RUN yum update -y && \
   yum install -y mesa-libGL && \
   python3.8 -m pip install -r requirements.txt -t .

# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]


これだけです。

試しにPOSTされた画像をグレースケール化して返す機能を書いてみます。

まずはtemplate.yamlでAPIが画像を受け付けることができるように指定します。また、Lambdaがコールドスタートした場合にはタイムアウトしてしまうことが多いため、Timeoutを30秒にしておきます。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
 python3.8

 Sample SAM Template for sam-opencv-app

Globals:
 Function:
   Timeout: 30

Resources:
 Api:
   Type: AWS::Serverless::Api
   Properties:
     StageName: Prod
     BinaryMediaTypes:
       - image/*

 GrayscaleFunction:
   Type: AWS::Serverless::Function
   Properties:
     PackageType: Image
     Events:
       Grayscale:
         Type: Api
         Properties:
           Path: /grayscale
           Method: post
           RestApiId: !Ref Api
   Metadata:
     Dockerfile: Dockerfile
     DockerContext: ./hello_world
     DockerTag: python3.8-v1

Outputs:
 Api:
   Value: !Sub "https://${Api}.execute-api.${AWS::Region}.amazonaws.com/Prod/grayscale/"


次にapp.pyに実際の処理を記述します。

import json
import base64
import cv2
import numpy as np


def lambda_handler(event, context):
   src_bytes = base64.b64decode(event["body"])
   src = cv2.imdecode(np.frombuffer(src_bytes, dtype=np.uint8), cv2.IMREAD_COLOR)
   gray = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY)
   _, gray_bytes = cv2.imencode(".jpg", gray)

   return {
       "statusCode": 200,
       "body": json.dumps(base64.b64encode(gray_bytes).decode("UTF-8")),
   }


ビルド・デプロイし、適当な手元の画像をPOSTしてみましょう。

```bash
$ sam build
...
$ sam deploy
...
$ curl -H "Content-Type: image/jpg" https://xxxxxxx.execute-api.<region>.amazonaws.com/Prod/grayscale/ --data-binary @test.jpg
```


Base64にエンコードされたグレースケール化した画像が返ってくるかと思います。

画像1

終わりに

今回AWS LambdaでPython + OpenCV環境を簡単に作ることが出来たように、コンテナイメージのサポートによってこれまでLambdaでは工夫がいる・難しいと思われていた処理を実行する環境の選択肢が増えました。(ただし既存のZip形式の上位互換ではないことに注意が必要です。)

参考になれば幸いです。

参考

AWS Lambda の新機能 – コンテナイメージのサポート

この記事が気に入ったらサポートをしてみませんか?