はじめに
LINEスタンプ用の画像を自動生成して、それをまとめてZIPでダウンロードできる仕組みを作りました。
構成はシンプルです。
・S3に画像を保存
・Lambdaで取得
・4x4に分割
・ZIPにまとめて再びS3へ
ただし…
Pillowとnumpyでかなりハマりました。
理由は Appleシリコン → Lambda(arm64) という環境差です。
👉 この記事はその記録です。
前回との違い(別の解決アプローチ)
前回は、PillowやnumpyをそのままLambdaに含める形で対応していましたが、
今回は構成を見直し、Layerを使った方法に変更しました。
具体的には、
・依存ライブラリ(Pillow、numpy)はLayerに分離
・Lambda本体は処理ロジックのみの軽量構成
・Dockerを使ってLambda環境に合わせたビルドを実施
という形にしています。
なぜこの方法に変えたか
前回の方法では、以下の課題がありました。
・デプロイサイズが大きくなりやすい
・ビルド環境によっては動かないことがある
・修正のたびにデプロイが重い
今回の方法にすることで、
・デプロイが高速化
・環境依存の問題を回避
・構成がシンプルに分離
といったメリットがありました。
やってみて感じたこと
最初はLayerやDockerの設定に少し手間取りましたが、
一度構成ができてしまえば、その後の開発はかなり楽になりました。
特に、デプロイ速度が大きく改善されたのは体感としても分かりやすく、
開発のストレスがかなり減りました。
やりたかったこと
rawフォルダにある画像を
Lambdaで取得して
Pillowで分割し
ZIPにまとめて
S3に保存する
最初の問題:Pillowが動かない
Lambdaで以下のエラーが出ました。
No module named ‘PIL’
解決しようとしてハマる
pip install pillow numpy をしてデプロイすると、
サイズ制限(250MB)に引っかかります。
Dockerでビルド
Dockerでビルドする際は、前回の記事を参考にしました。
特に、Lambda環境に合わせたライブラリのビルド方法について非常に参考になりました。
Lambda用の環境でPillowとnumpyをビルドするためにDockerを使いました。
ただしここでも問題が発生します。
numpyのビルドでコンパイラが見つからず失敗します。
解決
–only-binary=:all: を指定して、ホイールを強制使用することで解決しました。
次の問題:Layerのサイズ制限
Function code combined with layers exceeds 262MB
というエラーが発生しました。
解決:構成を分離
Lambda本体と依存ライブラリを分けました。
Lambda本体は軽量にし、
PillowとnumpyはLayerに分離します。
さらにハマる:Layerが効かない
No module named ‘PIL’
というエラーが再び発生。
原因はzipの構造でした。
正しいLayer構造
layer.zip の中に python フォルダが必要です。
pythonフォルダの中にPILやnumpyが入っている構造にします。
さらにハマる:importできない
NameError: name ‘Image’ is not defined
というエラーが発生。
解決
・sys.pathに /opt/python を追加
・from PIL import Image を正しく書く
・必要に応じて型ヒントの評価を遅延させる
完成構成
S3(raw)
→ Lambda(pack)
→ Layer(Pillow / numpy)
→ ZIP生成
→ S3(zips)
結果
1024x1024の画像を20分割できるようになりました。
ZIPも正常に生成されました。
デプロイも高速化されました。
学び
Layerはpythonフォルダ構造が重要
numpyはビルドが難しい
Dockerは非常に有効
Lambdaは軽量に保つべき
おわりに
最初は「なんで動かないの?」という状態でしたが、
試行錯誤を重ねて、最終的には画像を分割しZIPとして出力できるようになりました。
環境や構成によっては同じようにハマることもあると思います。
この記事が、どこかで困っている方のヒントになれば嬉しいです。
追記
もう一度layer.zip作ろうと思ったらすっかり忘れてしまっていたのでメモ
localで以下のフォルダを作る
mkdir -p layer/python
cd layer
dockerでビルド
docker run --rm -v "$PWD":/var/task public.ecr.aws/lambda/python:3.11
pip install pillow numpy -t python --only-binary=:all:
ビルド完了後にpythonフォルダをzip化
zip -r layer.zip python
lambdaにアップロードで完了
PILを使っているpythonファイルの上に以下を追加
import sys
sys.path.insert(0, "/opt/python")
