pyてよn日記

一寸先は闇が人生

AWS Lambda, Python: pipenv 仮想環境の deploy package を作成する

https://i.imgur.com/sV4dKZ3.png

 pipenv で作成した仮想環境のライブラリを deploy package(.zip ファイル)に取り込む方法を解説する.Docker 使うと楽らしいけど,筆者が使えないのでそれに関することは書けなかった.Docker に関する情報を求めてた人はごめんなさい.

アイキャッチAWS Lambda Python Development Package on Ubuntu 18.04 より引用)

前提

  • 実行環境:macOS Mojave 10.14.6
  • Python 3.7 系(3.7.3)
  • pipenv version 2018.11.26
  • .venv(仮想環境)をプロジェクトディレクトリ下に作っていること(以下の記事を参照)

dackdive.hateblo.jp

注意

 (投稿直前に急ぎで追加した項のため雑な内容になっている.)

 調べている途中に,本記事の内容が良くなさそうな気がしたのでこの「注意」の項を急遽追加.

 本記事では,手動で deploy package を作る方法を紹介している.しかし,記事を書いている途中に,yaml ファイルと requirements.txt を作ってコマンドを実行するだけで AWS Lambda(or S3)への zip ファイル(deploy package)のアップロードを自動化できるライブラリを見つけた.以下の(私の)ツイートの内容のリンクを参照.

 もう一つ参考になりそうな記事を見つけた.serverless-frameworkPythonプラグインとして serverless-python-requirements がある) という npm で配布されているパッケージで,デプロイ自動化,デプロイパッケージ容量を削減できる機能がある.こちらも yaml ファイルと requirements.txt で zip をアップロードできる.

dev.classmethod.jp

 自動化できる部分は自動化した方が良いので,本記事の手動で deploy package を作る方法は非効率だと思われる.上記の記事を参考にすることを勧める.本記事は供養目的である(ほぼ書き終わりだったため...).筆者は上記リンク先のツールに乗り換える予定.いずれこの記事も編集する(かもしれない).

 以上を踏まえた上で本記事を読み進めて欲しい.

導入

 AWS Lambda に Python の関数を登録するためには,関数が書かれたスクリプト,外部ライブラリを含めた .zip ファイルをアップロードする必要がある(標準ライブラリは必要ない).「外部ライブラリを含める」というのが注意点で,これは pip(env) install でインストールしたライブラリ例えば requests や numpy などのライブラリがこれに該当する.

 AWS Lambda 経由で API を叩いたり,数値計算を動かしたりなど,少し複雑なことをしたい場合には必ずライブラリが必須である.公式では zip ファイルの作り方を含めた,以下 2 つのアップロード方法が紹介されている.

  • pip install --target でローカルディレクトリにライブラリをインストール -> そのディレクトリごと zip 化 -> アップロード
  • virtualenv で作った仮想環境の site-packages(インストールしたライブラリが保存されているディレクトリ) を zip 化 -> アップロード

docs.aws.amazon.com

 本記事では,公式に無い pipenv で作った仮想環境のライブラリを含めた zip ファイルの作り方を解説する.

 中身としては,「.venvsite-packageAWS Lambda にアップロードする .zip ファイルに含める」だけであり,公式の virtualenv での方法とほぼ変わりがないが(site-package の場所が違うだけ?),覚書として残しておく.

pipenv 仮想環境のライブラリを zip 化

プロジェクトルートに移動し,.venv ディレクトリの存在を確認.

$ cd [プロジェクトルート]
$ ls -la | grep .venv
# drwxr-xr-x   9 user-name  staff    288  8  3 22:39 .venv

.venvsite-package を zip 化

  • zip 化 UNIX コマンド:zip -r [archive-name] [target-directory]
    (拡張子 .zip は勝手につけてくれる.自分でつけても良い.-r再帰オプション.)

 以下,プロジェクトルート下で実行するシェルスクリプト

zip_lambda_function.sh

#!/bin/bash

# pipenv 仮想環境を起動してから実行する
PROJECT_DIR=$(pwd)
SITE_PACKAGES_DIR=$(pipenv --venv)/lib/python3.7/site-packages

echo "Project Location: $PROJECT_DIR"
echo "Library Location: $SITE_PACKAGES_DIR"

# to zip site-packages
cd $SITE_PACKAGES_DIR
rm -rf __pycache__  # your option 容量節約のため.
zip -r $PROJECT_DIR/lambda.zip *

# add lambda-function script(.py)
cd $PROJECT_DIR
zip -g lambda.zip lambda_function.py  # zip に Python スクリプトを追加

# display zip file
ls | grep *.zip

 手順はとても単純.

  1. pipenv 仮想環境の site-packages ディレクトリを zip 化(lambda.zip
  2. AWS Lambda に登録する関数が書かれた Python スクリプトlambda_function.py)を zip に追加

※ ファイル名は分かりやすいように lambda という名前を使っているが自由に設定して良い.

 Python スクリプトを機能ごとにモジュール化している場合は,zip -g lambda.zip *.py のようにワイルドカード * を使って Python スクリプトを全て zip に追加すれば良い(自作パッケージの場合は手動でパッケージディレクトリごと追加すれば良いと思う).

 以上のシェルスクリプトを pipenv 仮想環境を起動させてから実行する.

$ cd [プロジェクトルート]
$ pipenv shell # 仮想環境の起動
(virtual-environment-name) bash-3.2$ sh zip_lambda_function.sh
# lambda.zip

 プロジェクトルート下に AWS Lambda にアップロードするための zip ファイルが作られている.

zip ファイルを AWS Lambda にアップロード

 最後に作成した zip ファイルを AWS Lambda にアップロードする.これに関してはネットに腐る程情報があるため各自でググり推奨(書くのがめんどい).参考になりそうな記事を貼っておく.

  • 公式:zip のアップロード方法(冒頭に貼ったのと同じ)

docs.aws.amazon.com

  • 公式:AWS Lambda の制限

本記事で問題になるのは,リンク先の「/tmp ディレクトリのストレージ」,「デプロイパッケージサイズ」の欄.前者はライブラリ,スクリプトなど全てを含めた上での AWS Lambda の最大容量(512 MB 以下)を表す.後者について,zip を直接アップロードする場合に 50 MB 以下という制限があるため注意が必要.

docs.aws.amazon.com

  • デプロイパッケージが容量オーバーの場合の対処法

numpy, pandas, sklearn など数値計算系のライブラリを zip 化すると 50 MB を超えてしまう.この場合,冒頭で紹介した serverless-framework を使って圧縮してデプロイするか,S3 に 512 MB 以下の zip ファイルを置き,関数実行時に解凍・展開してライブラリを使用するという 2 つの方法がある.後者の方法では,ライブラリを AWS Lambda のストレージ /tmp 下に展開するため,展開後の容量が 512 MB 以下という制限を守る必要があるため注意.以下が参考になる.

qiita.com

参考