前回、写真・画像ファイルを格納するS3バケットと、サムネイル画像を作成する処理コードを書いたのですが、画像編集に必要なPillowライブラリがLambda上ではロードできずに終わってしまいました。
[ERROR] Runtime.ImportModuleError: Unable to import module 'lambda_function': No module named 'PIL' Traceback (most recent call last):
今回はLambda上で追加ライブラリを読み込んで実行できるようにします。
Pythonの画像処理ライブラリ(Pillow)を準備
AWS Lambdaはサーバレスで実行されますが、裏側ではAmazonLinux2のインスタンス上で実行されているようですので、AmazonLinux2上でライブラリを準備する必要があります。
というわけで、EC2を使ってAmazon Linux2のインスタンスを一時的に立ち上げてライブラリの準備を行います。
Amazon Linux 2の環境を準備
EC2を使ってAmazon Linux 2のインスタンスを作ります。
作り方が分からない方は、こちらの記事を参考にしてみてください。この記事ではUbuntuで構築しましたが、Ubuntuを選択するところでAmazon Linux 2を選択すればほぼ流れは一緒です。
AmazonLinux2上での作業
ここからはAWS管理コンソールを一旦離れて、今作ったAmazonLinux2の仮想マシンを使って画像処理ライブラリを作成していきます。
Python 3.8 インストール
AmazonLinux2のインスタンスが作成できたら、SSHで接続します。
AmazonLinux2の初期ユーザは、ec2-userです。
ログインできたら、Python をインストールします。この記事執筆時点で最新の3.8で作りました。
必要なパッケージを追加
$ sudo yum install -y libtiff-devel libjpeg-devel libzip-devel freetype-devel lcms2-devel libwebp-devel tcl-devel tk-devel
Python 3.8 インストール
$ sudo amazon-linux-extras install -y python3.8
バージョン確認します。どちらも無事に3.8系が入りました。

Pillowライブラリ取得
pythonフォルダを作成して、その中に一式入手します。
Successfully installed Pillow-8.3.X が表示されれば完了です。
現在位置確認
$ pwd
/home/ec2-user
Pillowライブラリ取得
$ mkdir python
$ pip3.8 install Pillow -t python
Collecting Pillow
Downloading https://files.pythonhosted.org/packages/c5/f7/3084336272c2f1539ab36a117be4acf3131b967ff3a60e0ace06db151a7f/Pillow-8.3.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl (3.0MB)
100% |????????????????????????????????| 3.0MB 464kB/s
Installing collected packages: Pillow
Successfully installed Pillow-8.3.1
中身確認
$ ls -l python/
total 8
drwxrwxr-x 3 ec2-user ec2-user 4096 Jul 31 08:42 PIL
drwxrwxr-x 2 ec2-user ec2-user 118 Jul 31 08:42 Pillow-8.3.1.dist-info
drwxrwxr-x 2 ec2-user ec2-user 4096 Jul 31 08:42 Pillow.libs
Installing collected packages: Pillow
Running setup.py install for Pillow … error
このようなエラーが発生するとの報告を頂きました。
gccでビルドが必要というエラーが出るのでgccを入れてみたのですが、コンパイルエラー
結果、pip3.8ではなく、pipでインストールすると、Pillow8.4.0がインストールできました。
8.4.0の方はこの後の記載箇所、バージョン番号だけ読み替えてください。
ライブラリ一式をZIPファイルにまとめます。
$ zip -r9 Pillow-8.3.1.zip python
adding: python/ (stored 0%)
adding: python/Pillow.libs/ (stored 0%)
adding: python/Pillow.libs/libopenjp2-f0612b30.so.2.4.0 (deflated 72%)
(省略)
adding: python/Pillow-8.3.1.dist-info/WHEEL (deflated 22%)
adding: python/Pillow-8.3.1.dist-info/INSTALLER (stored 0%)
$ ls -l
total 3264
-rw-rw-r-- 1 ec2-user ec2-user 3341755 Jul 31 08:46 Pillow-8.3.1.zip
drwxrwxr-x 5 ec2-user ec2-user 66 Jul 31 08:42 python
$
Pillow-8.3.1.zip ファイルにまとまりましたね。
作成したライブラリファイル(ZIP)をダウンロード
あとは、作成したZIPファイルをAmazonLinux2インスタンスからSCP等を使って回収します。

AWS Lambdaにライブラリを追加
ここからはまたAWS管理コンソール上での作業となります。
Lambda関数としてZIPファイルから登録することもできますが、その場合ZIPファイルが大きいとAWSの管理コンソール上でLambdaのコードが編集できなくなってしまい不便なので、今回作ったライブラリZIPファイルはレイヤーとして登録します。
Lambda関数のライブラリとして登録
Lambdaの画面左側のナビゲーターから「レイヤー」をクリックします。

画面右側がレイヤー画面に切り替わりますので、「レイヤーの作成」ボタンをクリックします。

レイヤーを作成します。
①名前を付けます。ライブラリ名のようなイメージですので、後から分かりやすいものがよいです。入力可能な文字に制限がありますので、説明も書いておいたほうがよいでしょう。
②今回はさきほど作成したZIPファイルをアップロードしますので、.zipファイルの方を選択します。
③AmazonLinux2インスタンスからダウンロードしたライブラリが入ったZIPファイルを指定します。
④ランタイムはライブラリを作ったPythonの環境と同じバージョンが安心でしょう。
⑤最後に作成ボタンをクリックします。

このようなメッセージが表示されれば、ライブラリをレイヤーとして登録完了となります。

Lambda関数にレイヤー設定追加
今回作成した画像サイズ変更Lambda関数の「Layers」をクリックします。

画面が自動でスクロールして次のような画面が表示されますので、「レイヤーの追加」ボタンをクリックします。

さきほど追加したレイヤーを紐付けます。
①カスタムレイヤーを選択します。
②さきほどレイヤーとして登録したライブラリを選択します。
③バージョンを指定します。今回は初登録なので1を選択しました。
④追加ボタンをクリックします。

次のように表示されれば、画像サイズ変更Lambda関数から画像編集ライブラリ(Pillow)が認識できようになります。

動作確認
前回は動きませんでしたが、今回は動くことを祈って、S3バケットに画像ファイルを投げ込んでLambda関数を発動させてみましょう。
写真・画像ファイルのアップロード

私の好きな鉄塔写真で試してみます。写真ファイルをLambda関数のトリガーをセットしてあるS3バケットにアップロードします。
アップロードボタンを押して選んでもよいですし、この画面に直接ドラッグアンドドロップすることもできます。

前回は無反応で、CloudWatchで処理ログを確認したらPillowライブラリが見つからないというエラーが発生していたのですが、今回は無事にライブラリを認識できたようで、きちんと元画像を縮小したサムネイル画像をS3バケット上に出力されたようです。

自動生成されたサムネイルを確認
作成したサムネイル画像をダウンロードして確認してみましょう。

パソコンにダウンロードして、元のファイルとプロパティを比較してみました。
おお、ちゃんと半分のサイズになっていますね!

いかがでしたか?
これは便利ですね。ちょっとした処理ならEC2でインスタンス作らなくてもLambdaを使えば、ちょちょっと処理できてしまいます。サーバレスで気軽にPythonのコードが実行できるので、いろいろな使い方ができそうです。
サーバレス開発は盛り上がってきています。お客様からサーバレスでサービスを構築したいというオーダーも最近ではよく見かけます。是非、理解を深めて活用していきましょう。
プログラミング初心者は、技術本より教材の方が学習効率がよいと思います

コメント
参考にさせてもらいました。
この部分だけエラーでうまく動きませんでした。
pip3.8 install Pillow -t python
pip3だとうまくいきました。
通りすがりさん
ご覧いただきありがとうございます
確認してアップデートしたいと思います
情報ありがとうございます!