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にエンコードされたグレースケール化した画像が返ってくるかと思います。
終わりに
今回AWS LambdaでPython + OpenCV環境を簡単に作ることが出来たように、コンテナイメージのサポートによってこれまでLambdaでは工夫がいる・難しいと思われていた処理を実行する環境の選択肢が増えました。(ただし既存のZip形式の上位互換ではないことに注意が必要です。)
参考になれば幸いです。
参考
この記事が気に入ったらサポートをしてみませんか?