この記事の内容は古くて、例えば ARM Mac (Apple Silicon) ではうまくいかなかったりします。とはいえ Docker コンテナをビルドしたり起動したりする際に platform
オプションを指定すれば出来るとは思いますが、未確認です。
AWS Lambda の Python ランタイムでよく使うモジュールを Lambda Layers に登録しようと思ったが、EC2 インスタンスを立ち上げてパッケージを作るのが面倒なので Docker でできるようにした。
Lambda Layers とは何か
- ファイルを zip で固めたものをアップロードして「レイヤー」として登録することができる
- Lambda Function にレイヤーを追加すると、ランタイムの
/opt
以下に固めたファイルが展開されて実行時に利用できるになる - 言語ごとに指定された名前のディレクトリの中にモジュールを入れておくと、Lambda Function から読み込めるようにパスを通してくれる
- 例えば Python ランタイムの場合、レイヤー zip 内の
python
という名前のディレクトリに Python モジュールを入れておくと Lambda Function 側でそのモジュールをimport
で読み込むことができる
- 例えば Python ランタイムの場合、レイヤー zip 内の
詳しくは: AWS Lambda レイヤー - AWS Lambda
Layer を作成するための Docker イメージを作る
Python 3.8 ランタイムは Amazon Linux 2 で動いているらしい 1 ので、本来であれば Amazon Linux 2 の EC2 インスタンスを立ててその中でレイヤーを作るべきである (別に Linux ならなんでもいいかもしれないが、少なくとも macOS で作ったレイヤーは AWS Lambda では動かない 2 ) のだが、実は Amazon Linux は Docker Hub で公式イメージが配布されている 3 ので、これをベースにして Python 3.8 をインストールした Docker イメージを作ればわざわざ EC2 インスタンスを立てる必要がない。
FROM amazonlinux:2
ARG PYTHON_VERSION=3.8.7
RUN yum update -y && yum install -y tar gzip make gcc openssl-devel bzip2-devel libffi-devel \
&& curl https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz | tar xz \
&& cd Python-${PYTHON_VERSION} && ./configure && make && make install \
&& cd - && rm -rf Python-${PYTHON_VERSION}
ADD entrypoint.sh /
RUN yum install -y zip \
&& mkdir /python \
&& chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Entrypoint には pip install して zip で固めるスクリプトを登録しておく。
#!/bin/bash -eu
SRC=/python
DIST=/dist/layer.zip
pip3 install -t ${SRC} $@
rm -f ${DIST}
zip -q -r ${DIST} ${SRC}
イメージをビルドする。
$ docker build . -t bundle-pip-modules-for-aws-lambda-layers:python3.8
イメージ名が長ったらしいが別にここは何でもいい。
Docker イメージを使って Layer を作成する
例えば Pandas が使える Lambda Layer を作成する場合。
$ docker run --rm \
-v $(pwd):/dist \
bundle-pip-modules-for-aws-lambda-layers:python3.8 \
pandas
成功すればカレントディレクトリに layer.zip
が作成される。
上の例では直接 pandas
を指定したが、イメージ名以降の引数は pip3 install
で指定できる引数を全て渡せるので、例えば requirements.txt をマウントした上で -r
オプションを指定することで多くのモジュールをまとめて Layer にすることもできる。
$ echo 'pandas' > requirements.txt
$ docker run --rm \
-v $(pwd)/requirements.txt:/requirements.txt \
-v $(pwd):/dist \
bundle-pip-modules-for-aws-lambda-layers:python3.8 \
-r requirements.txt
Layer を登録する
作成された layer.zip
をアップロードする。
AWSCLI からアップロードする場合はこう。
$ aws lambda publish-layer-version \
--layer-name pandas \
--compatible-runtimes python3.8 \
--zip-file fileb://layer.zip
Layer を使用する
一番簡単な例として、Pandas の読み込み以外は何もしない Lambda Function を作ってみる。
import pandas
def lambda_handler(event, context):
pass
作った Lambda Function に登録した Layer を追加する。
この Lambda Function を実行してみてエラーが出なければ OK 。