
最近アーキテクチャレビュー会をしているときに「そういえば Amazon S3 Object Lambda ってあったな〜」という話になった😀
Amazon S3 Object Lambda は 2021年にリリースされてて,リリース直後に試した記憶はあるけど最近は使う機会がなかったな〜と思って,復習も兼ねて試してみることにした.
探したら楽しそうなチュートリアル「Using Amazon S3 Object Lambda to Dynamically Watermark Images as They Are Retrieved」があったのでやってみた❗️
何をするか
チュートリアルでは Amazon S3 Object Lambda を使って Amazon S3 にアップロードしてある画像を取得するときに透かし(ウォーターマーク)を追加して返す👌固定の透かしであれば事前に生成できるけど,透かしとして使う文字列がダイナミックに変化するような場合はリクエスト単位で生成したくなったりする.画像ではないけど電子書籍 (PDF) を購入するとメールアドレスが透かしで入っていることがあったりもしてそういう感じ📕
以下のような画像を取得できる❗️ちなみにチュートリアルでは「AWS ロゴ画像」に透かしを入れていて,何となく権利的に嫌だな〜😇と思って今回は適当に画像を作った.あと Watermark という固定文字列ではなく日付 (UTC) を追加するようにしてみた.

手順
チュートリアルの手順は以下のような感じ📝
- Step 1: Create an Amazon S3 bucket
- Step 2: Upload an object
- Step 3: Create an S3 Access Point
- Step 4: Create the Lambda function
- Step 5: Create an S3 Object Lambda Access Point
- Step 6: Download images from the S3 Object Lambda Access Point
- Step 7: Clean up resources
ちなみに AWS Lambda 関数で透かしを追加するのは Python の Pillow ライブラリを使っている🎨
追加課題
チュートリアルを楽しむために今回は個人的な追加課題として以下にも取り組んだ💪
- AWS Lambda 関数のランタイムを Python 3.9 → Python 3.12 に変更する
- Pillow ライブラリの AWS Lambda Layer を作らずに Klayers を使う
- マネジメントコンソールを使わずに AWS SAM でデプロイする
- 透かし(ウォーターマーク)を固定文字列ではなく日付 (UTC) にする
👾 template.yaml
AWS SAM テンプレートは以下のようにした📝(IAM Role は省略して既にあるものを使っている)
あと Klayers の ARN は Python 3.12(東京リージョン)AWS Lambda Layer 一覧 で取得した👌
AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Resources: Bucket: Type: AWS::S3::Bucket Properties: BucketName: sandbox-s3-object-lambda-hands-on AccessPoint: Type: AWS::S3::AccessPoint Properties: Bucket: !Ref Bucket Name: sandbox-s3-object-lambda-hands-on ObjectLambdaAccessPoint: Type: AWS::S3ObjectLambda::AccessPoint Properties: Name: sandbox-s3-object-lambda-hands-on ObjectLambdaConfiguration: SupportingAccessPoint: !GetAtt AccessPoint.Arn TransformationConfigurations: - Actions: - GetObject ContentTransformation: AwsLambda: FunctionArn: !GetAtt Function.Arn Function: Type: AWS::Serverless::Function Properties: FunctionName: sandbox-s3-object-lambda-hands-on CodeUri: src/ Handler: app.handler Runtime: python3.12 MemorySize: 256 Timeout: 10 Architectures: - x86_64 Role: arn:aws:iam::000000000000:role/xxxxx Layers: - arn:aws:lambda:ap-northeast-1:770693421928:layer:Klayers-p312-pillow:2
👾 src/app.py
AWS Lambda 関数コードは基本的にそのまま使いつつ,2個所修正した✔️
1つ目は Pillow で AttributeError: 'ImageDraw' object has no attribute 'textsize' というエラーが出るところ💨
-text_width, text_height = d.textsize(text, font) +text_bbox = d.textbbox((0, 0), text, font=font) +text_width = text_bbox[2] - text_bbox[0] +text_height = text_bbox[3] - text_bbox[1]
2つ目は透かしを日付 (UTC) にするところ📅
-img_result = add_watermark(img, parsed_qs.get('X-Amz-watermark', ['Watermark'])[0]) +img_result = add_watermark(img, parsed_qs.get('X-Amz-watermark', [str(datetime.datetime.now())])[0])
最終的なディレクトリ構成は以下のようにした.
$ tree . . ├── README.md ├── samconfig.toml ├── src │ ├── AmazonEmber_Rg.ttf │ └── app.py └── template.yaml 2 directories, 5 files
動作確認
$ sam build $ sam deploy
Amazon S3 Access Points・Amazon S3 Object Lambda Access Points などをデプロイできた👌(既にリソースは削除してある)

そして Amazon S3 バケットに kakakakakku-blog.png をアップロードしてから画像を取得する❗️--bucket には Amazon S3 バケット名ではなく「Amazon S3 Object Lambda Access Points エイリアス」を設定する.
$ aws s3api get-object \ --bucket sandbox-s3-object-la-sdsnt9xz1hsyxe4854zs8yfkapn1a--ol-s3 \ --key kakakakakku-blog.png \ watermarked-kakakakakku-blog.png
kakakakakku-blog.png

watermarked-kakakakakku-blog.png

動いたー \( 'ω')/