AWSをいじり倒す(13-2.lambda+serverless)
再びこちらの記事に戻ってきて
TensorFlowをAWS Lambdaで使って競艇予想APIを爆誕させました!! - Qiita
Serverlessを使ったlambda関数の定義。
果たしてこれで容量問題を掻い潜って関数が実行できるのか。
まずはやってみよう
さっそく、Serverlessを動かすためのnode.jsのインストール
2箇所エラーがでて詰まった
・1個目
Homebrewで「Warning: The following directories are not writable by your user:」とエラーが出た際の解消法 - Qiita
エラーメッセージに解決方法も書いてあるので、whoamiのところだけ書き換えて
コピペで解消
・2個目
Homebrewで「Warning: The following directories are not writable by your user:」とエラーが出た際の解消法 - Qiita
ディレクトリを作って解消。
どちらも記事の記載を淡々とこなせば解消したので特筆することはなし。
serverlessをインストール
npm install -g serverless
成功!
serverlessからAWSにアクセスするためのIAMアカウントを作成
プログラムによるアクセスを選択してユーザを作成。
AdministratorAccessを付与。
・・・なんか与えすぎな気もするが一旦作成。
lambdaにデプロイするときにcroud formation使ったりS3バケット作ったりと
いろんなことしまくるようなので、まとめてエイヤ権限ってことなんだろう。
ローカル端末から以下のコマンドを実行してserverlessからawsにアクセスできるようにする
serverless config credentials --provider aws --key [アクセスキーID] --secret [シークレットアクセスキー]
以下の文が返ってきたら成功
Serverless: Setting up AWS...
プロジェクトを作る。pythonを使うのでtemplateはaws-pythonを選択
コマンドを実行したディレクトリに
handler.py
serverless.yml
の2ファイルができた。
pyにはメインとなるlambda関数を、ymlにはデプロイするサービスの設定を書き込む。
lambda-layerとlambda-functionフォルダを作って、handler.pyとserverless.ymlをそれぞれのフォルダにコピーする
mkdir lambda-layer
mkdir lambda-function
cp handler.py lambda-layer/
cp serverless.yml lambda-layer/
cp handler.py lambda-function/
cp serverless.yml lambda-function/
lambda-functionの設定
vi lamda-function/serverless.yml
serverless-python-requirementsという機能を使って
追加のパッケージをインストールしてくれるらしいので、その設定を書く。
なお、serverless-python-requirementsを利用する場合、Dockerも必要となる
今回はインストール済みだったので手順は割愛
とはいえserverless.ymlのお作法はよくわからないので参考サイト通りに作成。
ただ、結局こっちでもslimPatternsにいらなさそうなファイルをずらずらと列挙して容量削減を図ることになる
service: [サービス名]
plugins:
- serverless-python-requirementscustom:
pythonRequirements:
dockerizePip: true
zip: true
slim: true
slimPatterns:
- "**/debug"
- "**/grpc"
- "**/h5py"
- "**/markdown"
- "**/pkg_resources"
- "**/setuptools"
- "**/tensorboard/plugins"
- "**/tensorboard/webfiles.zip"
- "**/tensorflow_core/contrib"
- "**/tensorflow_core/examples"
- "**/tensorflow_core/include"
- "**/tensorflow_estimator"
- "**/werkzeug"
- "**/wheel"
requirementsService: [サービス名]-layer
requirementsExport: [サービス名]Layer
requirementsLayer: ${cf:${self:custom.requirementsService}-${self:provider.stage}.${self:custom.requirementsExport}}provider:
name: aws
runtime: python3.7
stage: dev
region: ap-northeast-1
iamRoleStatements:
- Effect: "Allow"
Action:
- s3:ListBucket
- s3:GetObject
Resource:
- "arn:aws:s3::*"functions:
classify:
handler: handler.classify
memorySize: 2048
timeout: 60
layers:
- ${self:custom.requirementsLayer}
斜体太字部分は自分の環境に応じて書き換え。
handler.pyには実行したいプログラムを記載。
とりあえず動作確認をしたいので先頭に
try:
import unzip_requirements
except ImportError:
passimport json
import pandas
from keras.models import load_model
import numpy
をつけるだけつけた。
最初の4行はserverlessで必須、後半の4行で動作確認
requirements.txtを新たに作る
vi requirements.txt
そこに追加で入れたいパッケージを指定。
tensorflow == 1.14.0
lambda-layerの設定
service: [サービス名]-layer
plugins:
- serverless-python-requirementsprovider:
name: aws
region: ap-northeast-1
runtime: python3.7
stage: devcustom:
pythonRequirements:
dockerizePip: true
layer:
compatibleRuntimes:
- python3.7
slim: true
strip: falseresources:
Outputs:
[サービス名]Layer:
Value:
Ref: PythonRequirementsLambdaLayer
インデントとか空白とかその通りにしないとエラーが出るので注意
(これで数時間無駄にした)
こちらにも
requirements.txtを新たに作る
vi requirements.txt
そこに追加で入れたいパッケージを指定。
keras == 2.3.1
numpy == 1.18.1
pandas == 1.0.1
設定が終わったら以下のコマンドを実行してデプロイ。
cd lambda-layer
serverless deploy
cd ../lambda-function
serverless deploy
・・・
An error occurred: HandlerLambdaFunction - Unzipped size must be smaller than 64198656 bytes (Service: AWSLambdaInternal; Status Code: 400; Error Code: InvalidParameterValueException; Request ID: db8cece7-fd05-4e73-9066-d0921795792c).
というエラーが出て停止。
結局サイズが足りずにだめなんかーい
また容量との格闘か・・・
とりあえず組み合わせを変えてみる
具体的にはLayerのrequiementsを
numpy == 1.18.1
functionのrequirementsを
tensorflow == 1.14.0
keras == 2.3.1
pandas == 1.0.1
というふうに組み合わせを変えてみる
重複するパッケージがうまいこと作用することを祈って
Serverless: Checking Stack update progress...
...............
Serverless: Stack update finished...
う、うまくいった・・・。本当にギリギリの戦いだ
AWS lambdaにデプロイした関数ができているので、早速テスト
"errorMessage": "[Errno 28] No space left on device",
"errorType": "OSError",
はい、エラー
Lambda実行時に 'No space left on device'とエラーが出るときの対処法 - Qiita
tmpを使い切った模様。
果たして、この関数1つで使い切ったのか、トライアンドエラーしているうちに使い切ったのか・・・
とりあえずtmpをrmするコマンドを放り込む。
こ、コンソール上でプログラムの変更ができない・・・。
つまり毎回デプロイせなあかんのか!?
デプロイ1回に5分ぐらいかかるのでこれは地味にめんどくさい。
しょうがないので再デプロイ
→No space left on device
エラーメッセージを読むに、zip解凍した時点でtmp使い切っている疑惑。
頭抱えてたらまた新たな突破口を発見
新機能 – Lambda関数の共有ファイルシステム – Amazon Elastic File System for AWS Lambda | Amazon Web Services ブログ
いくつかのユースケースではLambda関数によって実装がより容易になります。例えば:
/tmp
で使用可能な容量(512MB)より大きいデータを処理またはロードする。
ど、ドンピシャ〜
しかも2020/6/17の記事て。最近すぎワロタ
械学習の推論を実装するLambda関数を作成するには、コード内で、必要なライブラリをインポートして機械学習モデルをロードできる必要があります。たいてい、そのようなことをすると、それらの依存関係の全体的なサイズは、デプロイメントパッケージサイズの現在のAWS Lambdaの制限を超えます。これを解決する1つの方法は、ライブラリを適切に最小化して関数コードとともにデプロイし、モデルをS3バケットからメモリ(モデルの処理に必要なメモリを含めて最大3 GB)または
/tmp
(最大512 MB)に配置します。このようなモデルのダウンロードとカスタムが必要な最小化は、実装するのが簡単ではありませんでした。しかし、これからはEFSを使用できます。
数日間悩んできたことが全部書いてあるしマジかよ。
もうlambdaやめようと思ってたけど、もうちょっと頑張る。
長くなってきたので次回へ