Lambda functions (Python) の 依存パッケージの保存場所を指定する
Lambda w/ Apex 関連でもう一つ TIPs を備忘録しておく。
Function hooks のおさらい
Apex には Function hooks という機構があり、 Apex で管理する Lambda function のライフサイクルの中で、特定のステップで任意の shell commands を発火させることができる。
以下は Apex.run に記載されている Sample だ。
Shell commands を指定できるので、当然 golang に限らずなんでも実行できる。当然 pip install
も可能。
hooks の種類は3種ある。
- build
- run before a function zip is built (use this to compile binaries or transform source)
- deploy
- run before a function is deployed (useful for testing, linting)
- clean
- run after a function is deployed (useful for cleaning up build artifacts)
なので、 Lamnbda Functions w/ Python の場合は以下のように build 時に pip install
して functions を梱包して deploy する function.json と requirements.txt を用意することが多いと思う。
pip install したパッケージ群のインストール先を変えたい
ただ、上の方法だと function directory に各パッケージがインストールされてしまう。 function 開発時において重要なものは function.json, Lambda の handler となる python code, あとは依存モジュール記す requirements.txt 。 その他のファイル群が同層に展開されるのは美しくないし、 gitignore 依存パッケージを一つ一つ指定する形になり面倒。
$ tree -L 4 . ├── README.mkd ├── functions │ └── helloworld-python │ ├── certifi │ ├── certifi-2017.7.27.1.dist-info │ ├── chardet │ ├── chardet-3.0.4.dist-info │ ├── function.dev.json │ ├── function.prd.json │ ├── function.stg.json │ ├── idna │ ├── idna-2.5.dist-info │ ├── main.py │ ├── requests │ ├── requests-2.18.2.dist-info │ ├── requirements.txt │ ├── urllib3 │ └── urllib3-1.22.dist-info ├── project.dev.json ├── project.prd.json └── project.stg.json
例えばこうしたい。
$ tree -L 4 . ├── README.mkd ├── functions │ └── helloworld-python │ ├── function.dev.json │ ├── function.prd.json │ ├── function.stg.json │ ├── main.py │ ├── requirements.txt │ └── site-packages │ ├── certifi │ ├── certifi-2017.7.27.1.dist-info │ ├── chardet │ ├── chardet-3.0.4.dist-info │ ├── idna │ ├── idna-2.5.dist-info │ ├── requests │ ├── requests-2.18.2.dist-info │ ├── urllib3 │ └── urllib3-1.22.dist-info ├── project.dev.json ├── project.prd.json └── project.stg.json
やりかた
ざっくり以下。
- function hooks を修正
- 環境変数 PYTHONPATH を指定
1. function hooks を修正
言うまでもないが、 pip install コマンドを微修正する。
- pip install -r requirements.txt -t ." + pip install -r requirements.txt -t ./site-packages"
2. 環境変数 PYTHONPATH を指定
site-packages を検索対象パスに追加する。
+ }, + "environment": { + "PYTHONPATH": "/var/runtime:/var/task/site-packages"
両方をまとめるとこうなる。
これで apex build
すれば、依存パッケージは ./site-packages/ 以下に保存されるようになり、かつ 依存パッケージにパスが通るようになる。
肝は
- 依存パッケージの path を /var/task/site-packages とすること
- /var/runtime も指定しておくこと
理由は以下に記す。
Lambda Functions を覗いてみる
pip install 時に指定した ./site-packages 以下のパッケージ群を検索対象するべくパスを通すために、展開先の挙動を把握しておく。
簡単な function を実行してみよう。
環境変数や実行ファイルのパスを除くだけのプログラムである。 この function のログはこんな感じとなる。
[INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 $ENV: environ({'APEX_FUNCTION_NAME': 'python-sample','LAMBDA_FUNCTION_NAME': 'hello-apex_python-sample', 'PATH': '/var/lang/bin:/usr/local/bin:/usr/bin/:/bin', 'LANG': 'en_US.UTF-8', 'TZ': ':UTC', 'LD_LIBRARY_PATH': '/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib', 'LAMBDA_TASK_ROOT': '/var/task', 'LAMBDA_RUNTIME_DIR': '/var/runtime', 'AWS_REGION': 'ap-northeast-1', 'AWS_DEFAULT_REGION': 'ap-northeast-1', 'AWS_LAMBDA_LOG_GROUP_NAME': '/aws/lambda/hello-apex_python-sample', 'AWS_LAMBDA_LOG_STREAM_NAME': '2017/08/31/[12]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'AWS_LAMBDA_FUNCTION_NAME': 'hello-apex_python-sample', 'AWS_LAMBDA_FUNCTION_MEMORY_SIZE': '128', 'AWS_LAMBDA_FUNCTION_VERSION': '1', '_AWS_XRAY_DAEMON_ADDRESS': '169.254.79.2', '_AWS_XRAY_DAEMON_PORT': '2000', 'AWS_XRAY_DAEMON_ADDRESS': '169.254.79.2:2000', 'AWS_XRAY_CONTEXT_MISSING': 'LOG_ERROR', '_X_AMZN_TRACE_ID': 'Root=1-xxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxx;Parent=xxxxxxxxxxxxxxxx;Sampled=0', 'AWS_EXECUTION_ENV': 'AWS_Lambda_python3.6', '_HANDLER': 'main.handle', 'PYTHONPATH': '/var/runtime', 'AWS_ACCESS_KEY_ID': 'ASIAXXXXXXXXXXXXXXXX', 'AWS_SECRET_ACCESS_KEY': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'AWS_SESSION_TOKEN': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==', 'AWS_SECURITY_TOKEN': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=='}) [INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 __file__ : /var/task/main.py [INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 $PYTHONPATH: /var/runtime [INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 sys.path: ['/var/task', '/var/runtime/awslambda', '/var/runtime', '/var/lang/lib/python36.zip', '/var/lang/lib/python3.6', '/var/lang/lib/python3.6/lib-dynload', '/var/lang/lib/python3.6/site-packages'] [INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 list /var/task/: ['site-packages', 'function.dev.json', 'main.py', 'requirements.txt', 'function.stg.json'] [INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 list /var/runtime/: ['s3transfer-0.1.10.dist-info', 'liblambdalog.so', 'dateutil', 'botocore', 's3transfer', 'boto3', 'six-1.10.0.dist-info', '__pycache__', 'botocore-1.5.89.dist-info', 'six.py', 'python_dateutil-2.6.1.dist-info', 'liblambdaio.so', 'liblambdaipc.so', 'boto3-1.4.4.dist-info', 'jmespath', 'awslambda', 'liblambdaruntime.so', 'docutils-0.13.1.dist-info', 'docutils', 'jmespath-0.9.3.dist-info'] [INFO] 2017-08-31T04:29:53.519Z 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 Received event: { "region": "ap-northeast-2" } END RequestId: 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 REPORT RequestId: 08d61df6-8e05-11e7-a88f-4d9fe5cb6d15 Duration: 17.21 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 20 MB null
ここから分かるのは、
- handler となる main.py の path は /var/task/main.py である
- /var/task に Upload した ZIP が展開される
- $PYTHONPATH には /var/runtime が元々セットされている
- /var/runtime には boto3 をはじめとした util 群 が存在する
つまり、 自分で pip install
したパッケージの保存先 ./site-packages
に path を通したければ PYTHONPATH に /var/task/site-packages
を追加すれば良い。
ただ、デフォルトで PYTHONPATH にセットされている /var/runtime
には boto3 をはじめとした util 群が含まれるので、このパスも有効にしておく。
なので、先程紹介した function.json のような形に行き着く。
実践AWS Lambda ~「サーバレス」を実現する新しいアプリケーションのプラットフォーム~
- 作者: 西谷圭介
- 出版社/メーカー: マイナビ出版
- 発売日: 2017/06/09
- メディア: 単行本(ソフトカバー)
- この商品を含むブログを見る