AWSのLambdaでPythonのライブラリを読み込みたいときに、一番簡単な方法として、ライブラリをzipにしてレイヤーにアップロードするという方法があります。
ただしこれには制限があって、解凍後に500MBまでのファイルしかアップロードできません。
その解決策としては、
- EFS(Elastic File System)を使う。
- LamdaをDockerにする。
という方法があります。
ここでは、より簡単な、EFSを使う方法をとった時のメモを残したいと思います(自分がやった時のメモなので、より良い方法があるかもしれません)。
まず、インバウンドルールをタイプ:NFS、ポート範囲:2049にしたセキュリティグループを作ります。
使用するEFSを用意します。
EFSの管理画面にアクセスし、右上の「ファイルシステムの作成」をクリックします。
適当な名前をつけて保存します。VPCはLambdaと同じにします。
ファイルシステムができたら、詳細画面の「ネットワーク」タブに移動し、「管理」をクリックします。
先ほど作ったセキュリティグループを割り当てて保存します。
「アクセスポイント」タブでアクセスポイントを作成します。例ではアクセス権限を777にしていますが、通常は755で良いと思います。
アクセスポイントのDNSをコピーしておきます。
EFSの作成はこれで完了です。
次に、EFS内に、ライブラリをインストールするディレクトリを用意します。
EFSへのライブラリのインストールはローカルからもできますが、Linuxからの方が良いとどこかで読んだので、今回はAWSのcluod9を使いました。
一応アップデート。
$ sudo yum -y update
この原稿の執筆時点ではcloud9にプリインストールされているPythonのバージョンは3.7でした。Lambdaでは3.9を使うので、cloud9にPython3.9をインストールします(Lambdaで使うバージョンに合わせます)。
まず、pythonのバージョン管理を行うpyenvをインストールします。
$ git clone git://github.com/yyuu/pyenv.git ~/.pyenv
pyenvにパスを通します。
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile
$ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
$ source ~/.bash_profile
確認。
$ pyenv --version
pyenvでpythonをインストールする際に必要な依存パッケージをインストールします。
$ sudo yum -y install gcc zlib-devel bzip2 bzip2-devel readline-devel sqlite sqlite-devel openssl-devel tk-devel libffi-devel
インストールできるPythonのバージョンを確認。
$ pyenv install -l
python3.9をインストール(例では3.9.15をインストールしています)
$ pyenv install 3.9.15
バージョンを切り替えます。
$ pyenv global 3.9.15
切り替わったか確認。
$ pyenv versions
これで下準備は整ったので、次はEFSをマウントします。
EFSをマウントするディレクトリを作成します。
$ sudo mkdir -p /mnt/efs
作成したディレクトリの所有者とグループを変更。
$ sudo chown -R ec2-user:ec2-user /mnt
先ほど作成したEFSのディレクトリをマウントします。
[EFSのアクセスポイントのDNS]には、先ほどコピーしたEFSのアクセスポイントのDNSを入れてください。
sudo mount -t nfs -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport [EFSのアクセスポイントのDNS]:/ /mnt/efs
マウントされていることを確認。
$ df -Th
マウントしたディレクトリに移動し、ライブラリをインストールするディレクトリを作成。
ライブラリをインストールするディレクトリ名はpythonにしないといけないという説があるので(試していないので真偽は不明)、そのようにしています。
$ cd /mnt/efs
$ mkdir -p lib/python
インストールディレクトリに移動。
cd lib/python
必要なライブラリをインストールします(以下は例です)。
$ pip install numpy -t ./
$ pip install pandas -t ./
$ pip install scikit-learn -t ./
次にLambda側の設定を行います。
設定タブのアクセス権限のところにEFSへのアクセス権限がある実行ロールを設定します。
次に、VPCを確認します。
セキュリティグループの設定で、EFSとの通信ができるようになっていなければなりません。
最後に、ファイルシステムで、先ほど作成したEFSを設定します。
ここまでできたら、LambdaにEFSを読み込む記述を追加します。
import sys
sys.path.append("/mnt/efs/lib/python")
import numpy as np
import pandas as pd
etc...
これでEFSにインストールしたライブラリがLamdaから使えるようになります。
ただし落とし穴があって、S3への読み書きをするためのs3fsというライブラリだけは、EFSからの読み込みができませんでした。
原因は不明ですが、とりあえずs3fsだけレイヤーにアップロードするという方法で回避しました。
あと、余談ですが、EFSにファイルを保存するときは、/tmpというディレクトリしか使えません。
これは名前の通り一時保存用のディレクトリで、あるLambdaで保存したものを別のLamdaで読み出して使う、といった使い方はできません。
そういうことをしたい場合は、LambdaのDocker化を行うと良いと思います(そうすれば10GBまでのファイルを保持できます)。
LambdaのDocker化については、別の機会に書きたいと思います。