AWS Lambdaでqrcodeとpillowを利用しQRコードを生成してみます。
実装自体は簡単なのですがLambadaのカスタムレイヤーの作成に手こずりました。
LambdaのランタイムにはPython3.8を利用します。
利用ライブラリについて (qrcode/pillow)
qrcodeとpillowはLambda標準ライブラリに含まれていないのでカスタムレイヤーとして追加します。
pillowはOS依存があるのでレイヤー用のZipを作成する際はLambdaのPython実行環境と同じOSで作成する必要があります。
実行環境は言語やバージョンによって異なります。詳細は以下リンク先を参照ください。
Lambda ランタイム
今回はAWS SAM用に用意されたDockerコンテナを利用してレイヤーを作成します。
事前準備 Docker
今回はCloud9上でレイヤーの作成を行います。
Cloud9では標準でDockerがインストールされているはずです。以下で確認します。
# バージョン確認
docker --version
# サービスの実行状態確認
sudo docker info
# 自分がDockerグループに所属しているか確認。「docker」が含まれていればOK.
groups
# 動作確認
docker run hello-world
カスタムレイヤーの作成
以下の構造でフォルダと「requirements.txt」を作成します。
├── requirements.txt
└── python/
└── lib/
└── python3.8/
└── site-packages/
requirements.txtには必要なライブラリを記載します。今回は以下の2つです。
qrcode
Pillow
準備したフォルダにライブラリをインストールします。
docker run -v "$PWD":/var/task "public.ecr.aws/sam/build-python3.8" /bin/sh -c "pip install -r requirements.txt -t python/lib/python3.8/site-packages/; exit"
インストールしたライブラリをZIP化します。
zip -r qrcodelibs.zip python > /dev/null
レイヤーを更新します。
aws lambda publish-layer-version --layer-name qrcodelibs --description "qrCodelibs" --zip-file fileb://qrcodelibs.zip --compatible-runtimes "python3.8"
作成したレイヤーを使用するようにLamba関数を更新します。
レイヤーのARNとLambda関数名は環境に合わせて変更してください。
aws lambda update-function-configuration --layers arn:aws:lambda:us-east-1:xxx:layer:qrcodelibs:1 --function-name my-function
QRコードの生成(SVG形式)
QRコードを生成するLambda関数です。
Lambdaプロキシ統合の場合はBase64での返却が必須なので
生成したデータをBase64形式にしてから送信します。
import io
import qrcode
import base64
import qrcode.image.svg
def lambda_handler(event, context):
encoded_image = make_base64_svg('qrtest')
return {
"statusCode": 200,
"headers": {"Content-Type": 'image/svg+xml'},
# "headers": {"Content-Type": "image/png"},
# Lambdaプロキシ統合の場合はBase64での返却が必須
"isBase64Encoded": True,
"body": encoded_image
}
def make_base64_svg(data):
qr = qrcode.QRCode(
box_size=400,
border=2,
)
qr.add_data(data)
qr.make(fit=True)
img = qr.make_image(image_factory=qrcode.image.svg.SvgPathImage,fill_color="black", back_color="white")
buffered = io.BytesIO()
img.save(buffered)
buffered.flush()
base64str = base64.b64encode(buffered.getvalue()).decode("utf-8")
return base64str
QRコードの生成(PNG形式)
PNG形式の場合は下記のようになります。フォーマット指定が変更になるだけです。
def make_base64_png(data):
qr = qrcode.QRCode()
qr.add_data(data)
qr.make()
img = qr.make_image()
buffered = io.BytesIO()
img.save(buffered, format="PNG")
base64str = base64.b64encode(buffered.getvalue()).decode("utf-8")
return base64str
APIGatewayで画像返却する際の注意点
AWS Lambda プロキシ統合のバイナリペイロードを処理するには、関数のレスポンスを base64 でエンコードする必要があります。
また、API の binaryMediaTypes を設定する必要があります。
参考
- Docker でシミュレートされた Lambda 環境を使用して、Lambda レイヤーを作成する方法を教えてください。
- AWSが公式リリースしているAWS SAM用のコンテナイメージは以下で公開されています。
https://hub.docker.com/search?q=amazon%2Faws-sam-cli-build&type=image - Lambda レイヤーの作成と共有
以上