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 の実行環境

AWS Lambda Runtimes - AWS Lambda

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

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

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

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

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

amazonlinux - Docker Hub

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

  • 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/resize-s3-image: This function resizes the image in Amazon S3. This function is supposed to be called by Amazon S3 Batch Operations.


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

Share to ...

Follow on Feedly

comments powered by Disqus