この記事の内容は古くて、例えば ARM Mac (Apple Silicon) ではうまくいかなかったりします。とはいえ Docker コンテナをビルドしたり起動したりする際に platform
オプションを指定すれば出来るとは思いますが、未確認です。
AWS Lambda が Python 3.6 をサポートしたとのことなので、今まで Node.js で書いていた Lambda Function を Python で書いてみることにしたのだけれど、numpy などの C で書かれたモジュールを含んだ Lambda Function を Mac からデプロイすると 「それは Mac 用にビルドされたモジュールだから読み込めんよ」 などと言われて Lambda 上で実行できないくてつらい。
この問題を Docker で解決したのでその方法についてまとめる。
[2020.03.25 追記] Lambda Layer を作成する方法についても書いた。
Docker で AWS Lambda の Python 用 Layer を作成する - Qiita
デプロイしたい Lambda Function の例
今回は、以下のような numpy を読み込む以外何もしない Lambda Function をデプロイすることを考える。
.
├── main.py
└── requirements.txt
import numpy
def handler(event, context):
pass
numpy
Mac 上で普通にインストールした場合
以下のコマンドを実行すると同じディレクトリに numpy がインストールされるが、これでインストールされたものを zip に固めてデプロイしても numpy が Mac 用のビルドなので Lambda 上では動かない。
$ pip install -r requirements.txt -t .
たぶんこんなエラーが出るはず。
Unable to import module 'main':
Importing the multiarray numpy extension module failed. Most likely you are trying to import a failed build of numpy.
If you're working with a numpy git repo, try `git clean -xdf` (removes all files not under version control). Otherwise reinstall numpy.
Original error was: cannot import name 'multiarray'
解決策をググると「Amazon Linux インスタンスを立ち上げてそこでビルドする」みたいな謎の回答しか出てこない。AWS Lambda でサーバーレスしたいのにデプロイにサーバが必要とはこれ如何に???
要は Linux 環境でビルドできればいいんじゃ。
それ Docker でできるよ。
Docker コンテナ上でビルドする
先程のコマンドを Docker コンテナ上で実行するには以下のようにすればよい。
$ docker run --rm -v $(pwd):/work -w /work python:3.6 pip install -r requirements.txt -t .
Python 3.6 のイメージ1からコンテナを起動して、作業ディレクトリ /work
にカレントディレクトリをマウントして、そこでパッケージをインストールする。ビルドが完了したらもうこのコンテナは不要なので --rm
オプションをつけて削除されるようにしている。
これで Linux 環境でビルドされた numpy が手に入ったので、あとはこれを固めてデプロイすれば動くはず。
どうやって開発すればいいか
「Linux 用のモジュールをインストールしてしまったら今度は開発時に Mac 上で実行できないじゃないか」と思うかもしれない。
確かに Mac 上では動かすことはできないが、開発するときも全部 Docker コンテナに乗せて実行すればいいと思う。
$ docker run --rm -v $(pwd):/work -w /work python:3.6 python -c 'import main; main.handler({}, None)'
こんな感じで。
-
python:3.6
イメージはベースが Debian なので Lambda の実行環境 (Amazon Linux) とは違うのだけど、インストールされたのがnumpy-1.13.1-cp36-cp36m-manylinux1_x86_64.whl
だったので Linux ならなんでもいいんだと思われる。numpy 以外のモジュールでダメなやつがあるかもしれないが、その場合は Amazon Linux の Docker イメージを落としてきてやればよい。 ↩