はじめに
- AWS LambdaでのOpenCVの環境構築は、大変です。具体的には、デプロイ環境の構築が大変です。
- デプロイ環境は、
AWSCLI
、Serverless Framework
等色々な物が必要です。 - 今回も、以前作成した顔認識アプリをLambdaへ移植します。ソースコードは、同一です。上記のデプロイに関する設定ファイルが異なる程度です。
- ソース一式は ここ です。
概要
- Mac
- 顔認識アプリ
- Flask
- OpenCV
- Python
- デプロイツール等
- AWSCLI
- Docker
- Homebrew
- Node.js
- Serverless Framework
- 顔認識アプリ
- AWS
- API Gateway
- CloudFormation
- CloudWatch
- IAM
- Lambda
- S3
Homebrew
- まず、各種ツールインストールのためのHomebrewを入れます。
- これは、説明割愛でOKですよね?
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
AWSCLI
- AWSでIAMユーザーを作ります。今回は、
serverless
にしました。 - プログラムによるアクセスを有効にします。
- アクセス許可は、AdministratorAccessにします。
- アクセスキーIDとシークレットアクセスキーを控えます。
- AWSCLIをインストールして、上記のアクセスキーIDとシークレットアクセスキーを登録します。
- リージョンは、東京(ap-northeast-1)にしました。
- ユーザー一覧を表示で出来るはずです。
$ brew install awscli
$ aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Default region name [None]: ap-northeast-1
Default output format [None]:
$ aws iam list-users
Node.js
- Node.jsをインストールします。これは、後述のServerless Frameworkをインストールするためです。
- npmと言う、パッケージ管理システムもインストールされるはずです。
$ brew install node
Serverless Framework
- Serverless Frameworkは、各種クラウド(AWS、Azure、GCP等)でサーバレス環境構築を簡単にしてくれます。
- Flaskのための、WSGIやrequirements.txtのプラグインも有り、かなり楽が出来ます。
- 正直、これが無いとコントロールパネルポチポチで相当辛いと思う。
インストール
- npmでserverlessをインストールします。
$ npm install -g serverless
プロジェクト作成
- python3のプロジェクトを作成します。
- プロジェクト名とフォルダ名は、
flask_opencv
にしました。 -
handler.py
は、参考で作成されます。今回は、顔認識アプリのmain.py
を利用するので、削除します。 -
serverless.yml
は、この後書き換えます。
$ serverless create --template aws-python3 --name flask_opencv --path flask_opencv
省略
Serverless: Successfully generated boilerplate for template: "aws-python3"
package.jsonの作成
- パッケージ管理用の
package.json
を作成します。
$ npm init -f
{
"name": "flask_opencv",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
プラグインのインストール
serverless-wsgi
- Flask、DjangoやPyramid等のWSGIアプリのためのプラグインです。
- Lambdaでは、LambdaとFlaskの間にこのWSGIプラグインを使うのが人気の様です。
- HerokuやGoogle App Engineでは、
Gunicorn
を使いました。
- HerokuやGoogle App Engineでは、
- https://github.com/logandk/serverless-wsgi
serverless-python-requirements
- requirements.txtを元に関連ライブラリをまとめてくれます。
- デプロイ時にDockerを活用する事で、OpenCVの様なライブラリも利用可能にしてくれます。
serverless-apigw-binary
- API Gatewayで、送受信時にバイナリデータを扱うための設定をしてくれます。
- API Gatewayは、デフォルトでは、テキストでデータを扱うため、画像等の場合は、そのまま扱う様にする必要があります。
インストール
- 上記3種をインストールします。package.jsonに追加されるはずです。
$ npm install --save-dev serverless-wsgi serverless-python-requirements serverless-apigw-binary
$ cat package.json
{
"name": "flask_opencv",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"serverless-apigw-binary": "^0.4.4",
"serverless-python-requirements": "^5.0.1",
"serverless-wsgi": "^1.7.3"
}
}
serverless.yml
- 今回の設定ファイルの中心ファイルです。ここに、デプロイの設定を記載します。
- service: は分かりやすい名前を適当につけてOKです。ただし、
_
など使えない文字が有ります。 - provider: は、AWS、Python3.7、東京リージョン、タイムアウトは30秒など指定します。
- provider: stage: は、デフォルトで
dev
が指定されます。場合に応じてstg
やprod
などへ変更して下さい。 - plugins: は、上記でインストールしたプラグインを記載しています。
- functions: main: handler: は、
wsgi_handler.handler
を指定します。つまり、Lambdaは、serverless-wsgiを経由してFlaskへアクセスする事になります。 - functions: main: events: は、httpのすべてのアクセスを通過させています。
- custom: wsgi: app: は、
main.py
のapp
を対象とするようにします。 - custom: pythonRequirements: dockerizePip: は、Dockerを使って、requirements.txtのライブラリをパッケージします。このおかげで、OpenCVを利用できる様になります。
- custom: apigwBinary: types: は、API Gatewayでバイナリデータをテキストデータへ変換しない様にするためのものです。今回は、顔画像の送信は、POSTで
multipart/form-data
を使います。顔画像の受信は、生jpegなのですが、image/jpeg
ではうまく行かず、text/html
を追加したらOKでした。このあたりの理由は、調べきれていません。
$ cat serverless.yml
service: flask-opencv
provider:
name: aws
runtime: python3.7
# stage: dev
region: ap-northeast-1
timeout: 30
plugins:
- serverless-apigw-binary
- serverless-python-requirements
- serverless-wsgi
functions:
main:
handler: wsgi_handler.handler
events:
- http: ANY /
- http: ANY {proxy+}
custom:
wsgi:
app: main.app
packRequirements: false
pythonRequirements:
dockerizePip: true
apigwBinary:
types:
# - 'image/jpeg'
- 'multipart/form-data'
- 'text/html'
Docker
- あと少しでデプロイ出来ます。
- 上記で、
serverless-python-requirements
のDocker機能を利用してOpenCVのライブラリを利用すると話ました。 - Install Docker Desktopを参考にインストールして下さい。
- もしくは、下記でもOKなはずです。
$ brew install docker
顔認識アプリ
- 以下で解説したものと同一です。解説は、こちらを参照して下さい。
デプロイ
- いよいよ、デプロイです。
- requirements.txt を読み込んで、Docker Image lambci/lambda:build-python3.7 を利用して
docker run
しています。 - そのあと、CloudFormationを利用して、S3バケットを作成し、ソース、パッケージ等のzipがアップロードされています。
- 引き続き、CloudFormationがIAMロール、API Gateway、CloudWatch、Lambdaを作成します。
- 作成が終わると、エンドポイントが表示されます。
$ serverless deploy -v
省略
Serverless: Stack update finished...
Service Information
service: flask-opencv
stage: dev
region: ap-northeast-1
stack: flask-opencv-dev
resources: 12
api keys:
None
endpoints:
ANY - https://dlhkrgpmfi.execute-api.ap-northeast-1.amazonaws.com/dev
ANY - https://dlhkrgpmfi.execute-api.ap-northeast-1.amazonaws.com/dev/{proxy+}
functions:
main: flask-opencv-dev-main
layers:
None
動作確認
- 上記のエンドポイントへアクセスします。
- 画像(jpeg)と処理回数(1〜100)を送信し、顔認識の画像を受信します。
- 処理回数は、性能評価用に準備したものです。今回は、10回にします。
送信画像
- 顔認識に使う画像は、一部界隈ではおなじみの顔画像を使いました。
- Heroku用アプリ、Google App Engine用アプリで利用した物と同じです。
ログの確認
- 今回は、約9秒でした。1回あたり、0.9秒ですね。Google App Engineよりは速く、Herokuよりは遅いって感じか。
- まぁ、時間帯や色々違うし、参考程度にしておきます。
$ serverless logs -f main
START RequestId: f88920f5-27d1-417f-bada-4bafde912fc2 Version: $LATEST
opencv version: 4.1.1, elapsed second: 9.593120813369751
おわりに
- AWS LambdaでFlaskとOpenCVを使う方法と動作確認をしました。
- 正直、Serverless Frameworkや関連プラグインが無いと辛いんだろうなぁと思いました。しかし、これらのおかげで、コントロールパネルをポチポイせずに簡単な作業となりました。
- あと、エンドポイントに関しては、Serverless Domain Managerを使うと、ドメインを利用出来たり、パスを修正出来そうです。
- 今後は、Azureで同様の事をやってみたいと思います。