やろうとしたこと
タイトルの通り、Serverless-Frameworkを使用してAWS Lambdaへデプロイすることを考えていた。 細かい話としては
- ランタイムにPython
- サードパーティのモジュールを使用
- エントリポイントは複数モジュールに分割
一般的であるが、このような状況だった。 以下では更に具体的な状況について記載していく。
ディレクトリ構造
$ tree src/ src/ ├── exception.py ├── gcs.py ├── handler.py └── lib
serverless.yaml
service: test_deploy provider: name: aws runtime: python3.7 stage: ${opt:stage,'dev'} region: ${opt:region,'ap-northeast-1'} profile: ${env:AWS_PROFILE,'default'} functions: testapp: role: arn:aws:iam::**************** handler: src/handler.lambda_handler name: test_app description: deploy_test runtime: python3.7 memorySize: 128 timeout: 30 tracing: False environment: stage: dev test_env: example tags: Name: test_deploy events: - s3: bucket: test_bucket events: s3:ObjectCreated:* existing: true package: include: - src/** exclude: - ...
ここでのハマりポイント4点
- アップロード後のディレクトリ構造
- ハンドラの指定方法
- 新機能:既存のs3バケットへのイベント割当
- Pythonのサードパーティモジュールが見つからない(unable import to ***)
1. アップロード後のディレクトリ構造
Serverless-Frameworkではserverless.yaml
のpackage
ディレクティブでアップロードするファイルをしている。
コンソールからzipでアップロードする場合もおそらく同じだが、アップロード後は/var/task/
以下に展開される。
例えば上記の例ではpackage
ディレクティブで指定しているディレクトリ構造そのままでアップロードされるので、例えばハンドラの場所は
/var/task/src/handler.py
となる。
2. ハンドラの指定方法
Lambdaではエントリポイントとなる関数を指定する必要があり、severless.yaml
でもhandler
ディレクティブで指定している。
具体的にどう指定するか、については今回のhandler.py
内のlambda_handler()
をエントリポイントとしたいとすると、src/handler.lambda_handler
のように指定すればよい。
/var/task
はワーキングディレクトリのため記載の必要ない。(おそらく動かなくなる)
3. 新機能:既存のs3バケットへのイベント割当
実は最近?ではないがこれまでなかった機能として既に存在するS3バケットのイベントを割り当てることができない問題があった。
(これまではプラグイン:serverless-plugin-existing-s3
を使用していた。)
今回からexisting
ディレクティブをtrue
とすることでそれが可能となる。
ただし、当機能で割り当てられるバケットは1つのみなので注意が必要。
複数割り当てたい人はこれまで通りプラグインでの対応が必要になる。
4. Pythonのサードパーティモジュールが見つからない(module *** not found error)
これは結論PYTHONPATHが通っていないことが原因で発生する。
デフォルトでは/var/task
まではパスは通っているのだが上記のようにsrc/
以下になるとモジュールが見つからなくなる。
この場合は以下のようにPYTHONPATHを追加しよう。
import sys sys.path.append('/var/task/src')
もしかしたらserverless.yaml
のenvironment
ディレクティブでPYTHONPATHに追加するような記載をすればスマートに追加可能かもしれないが試してはいない。→ためしたところうまくできた。環境変数にPYTHONPATH
を指定して、今回の例では/var/task/src
を記載すれば正しく設定されていた。
import周りを最適化するisort
を使用すると、上記のsys.append(...)
でのPYTHONPATH調整は使えなくなるので、できるだけ予めPYTHONPATHを通すような実装としたい。