Mac だけど Python で AWS Lambda したい!

  • 21
    いいね
  • 0
    コメント

AWS Lambda が Python 3.6 をサポートしたとのことなので、今まで Node.js で書いていた Lambda Function を Python で書いてみることにしたのだけれど、numpy などの C で書かれたモジュールを含んだ Lambda Function を Mac からデプロイすると「それは Mac 用にビルドされたモジュールだから読み込めんよ」などと言われて Lambda 上で実行できないくてつらい。

この問題を Docker で解決したのでその方法についてまとめる。

デプロイしたい Lambda Function の例

今回は、以下のような numpy を読み込む以外何もしない Lambda Function をデプロイすることを考える。

ディレクトリ構成
.
├── main.py
└── requirements.txt
main.py
import numpy

def handler(event, context):
    pass
requirements.txt
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)'

こんな感じで。


  1. python:3.6 イメージはベースが Debian なので Lambda の実行環境 (Amazon Linux) とは違うのだけど、インストールされたのが numpy-1.13.1-cp36-cp36m-manylinux1_x86_64.whl だったので Linux ならなんでもいいんだと思われる。numpy 以外のモジュールでダメなやつがあるかもしれないが、その場合は Amazon Linux の Docker イメージを落としてきてやればよい。