kakakakakku blog

Weekly Tech Blog: Keep on Learning!

S3 Object Lambda に入門できるチュートリアル「Using Amazon S3 Object Lambda to Dynamically Watermark Images as They Are Retrieved」

最近アーキテクチャレビュー会をしているときに「そういえば Amazon S3 Object Lambda ってあったな〜」という話になった😀

Amazon S3 Object Lambda は 2021年にリリースされてて,リリース直後に試した記憶はあるけど最近は使う機会がなかったな〜と思って,復習も兼ねて試してみることにした.

docs.aws.amazon.com

探したら楽しそうなチュートリアル「Using Amazon S3 Object Lambda to Dynamically Watermark Images as They Are Retrieved」があったのでやってみた❗️

aws.amazon.com

何をするか

チュートリアルでは 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) にする

github.com

👾 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

動いたー \( 'ω')/

関連記事

aws.amazon.com

aws.amazon.com