TL;DR

Lamnbda のデプロイパッケージに含める Pillow のライブラリ群は、 Amazon Linux 2 でインストールしたものを使用する。
Pillow に限らず、Lambda 関数に外部パッケージ (ライブラリ) を含める場合は、 OS 依存の有無に注意が必要。

何がしたかったのか

やりたかったこと

S3 に保存してある画像に対して、 S3 Batch Operations で Lambda を呼んでリサイズをする。

割とよくあるオペレーションだと思うんですが、調べてみると Node.js でやってるパターンばかりで Python でやってるパターンが見つけられませんでした。なので、リサイズ処理用の Lambda 関数は Python で実装してみることにしました。
ランタイムは Python 3.7 にします。

やったこと

Python での画像処理には Pillow を使うと楽なので、今回も Pillow を使うことにします。
Lambda の Python 実行環境には Pillow は存在しないので、ローカルでインストールしたライブラリ群をデプロイパッケージとして zip ファイルにまとめて Lambda にアップロードする必要があります。
Pillow は pip でインストールします。

$ pip3 install Pillow -t dist/

デプロイパッケージにはメインの python ファイルも含めます。

dist
├── PIL
├── Pillow-6.0.0.dist-info
└── lambda_function.py

上記のようなフォルダを zip 化して Lambda にアップロードします。

起こったこと

いざアップロードした関数を実行してみると、次のようなエラーが出ました。

[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': cannot import name '_imaging' from 'PIL' (/var/task/PIL/__init__.py)

ローカル環境では起こっていなかったエラーです。

解決するまでの流れ

色々試してみる

解決するまでに確認・試したことは次のようなことです。

  • ローカルと Lambda のランタイムの Python バージョンを合わせる
  • Python 3.6 でやってみる

これでは解決しませんでした。

調べてみると、どうやら Pillow のライブラリ群にはインストールする OS に依存する部分があることがわかりました。ということは、 Lambda が実行される環境と同じ環境でインストールした Pillow が必要ということにあります。

Lambda の実行環境

上記ページにもあるように、 Lambda の実行環境 (OS) は Amazon Linux です。なので、 Amazon Linux 上でインストールした Pillow が必要になります。

Amazon Linux 上でインストールした Pillow の取得

シンプルというか、まず思い浮かべるのは Amazon Linux の EC2 インスタンスを立てて、そこでインストールした Pillow を使う方法です。
ただ、これだけのために EC2 インスタンスを立てるのは面倒で、且つ多少なりとも料金が発生してしまいます。

ここで使うのが Docker ですね。 ドッカードッカー言われてもう結構経ちますが、まだほとんど触ったことがなかったので良い機会になりました。

Amazon Linux の docker イメージは dockerhub で公開されているので、それを使います。

やりたいことは以下の通りです。

  • Python 3.7 をインストールした Amazon Linux のコンテナを作成する
  • Amazon Linux コンテナ内で、ホストと同期したディレクトリに Pillow をインストールする

です。

Dockerfiledocker-compose.yml は次のような感じです。

FROM amazonlinux:latest

RUN yum install python3 -y
RUN mkdir /home/deploy
version: '2'
services:
  app:
    build: .
    volumes:
      - './deploy:/home/deploy'
    command: pip3 install -r /home/deploy/requirements.txt -t /home/deploy/dist

これを下記のようなディレクトリ構成にして docker-compose up --build を実行すると、 dist ディレクトリに Amazon Linux 環境でインストールした Pillow のライブラリが保存されます。 (というか同期してるのでここにインストールされる)

.
├── Dockerfile
├── deploy
│   ├── dist
│   └── requirements.txt
└── docker-compose.yml

あとは、ライブラリ群と Python ファイルを zip 化してアップロードすれば ok です。

無事に Lambda で Pillow が使えた

AWS Lambda で Pillow を使おうとしたらハマった話でした。なんとか無事に Pillow を使うことができました。
そして S3 Batch Operations で数万件の画像が一瞬でリサイズされて、すげーってなってました。

今後はデプロイパッケージに含める外部ライブラリについては、 OS 依存の有無に限らず Amazon Linux 環境でインストールしたものを使うようにしたいと思います。

実際にできあがっものは GitHub に置いています。


以上、よっしー (michimani) でした。

Share to ...

0

Follow on Feedly

comments powered by Disqus