DVA

S3に画像アップロードをトリガーにLambda関数を実行してサムネイルを作成する

スポンサーリンク
S3に画像アップロードをトリガーにLambda関数を実行してサムネイルを作成する DVA
スポンサーリンク
スポンサーリンク

S3バケットへの画像アップロードをトリガーにして、Lambda関数を実行してサムネイルを作成する

S3が提供する機能の1つに、イベント通知機能があります。

Amazon S3 イベント通知機能を使用して、S3 バケットで特定のイベントが発生したときに通知を受け取ることができます。

Amazon S3 イベント通知

今回はS3イベント通知をトリガーにして、Lambda関数を実行することを考えます。
具体的には、以下のAWS公式のチュートリアルで取り上げられている構成を再現します。

チュートリアル: Amazon S3 トリガーを使用してサムネイル画像を作成する - AWS Lambda
このチュートリアルでは、Lambda 関数を作成し、Amazon Simple Storage Service (Amazon S3) のトリガーを設定します。Amazon S3 は、S3 バケットにアップロードされる各画像ファイルの CreateThumbnail 関数を呼び出します。この関数は、ソース S3 バケッ...

S3バケットに画像がアップロードされると、そのイベント通知をトリガーとして、サムネイルを作成するLambda関数が実行されます。

構築する環境

Diagram of trigger image upload to S3 invokes Lambda function to create thumbnails.

2つのS3バケットを作成します。

一方のバケットは、ユーザからアップロードされた画像を保存するバケットです。
このバケットは通知機能を有効化します。

もう一方のバケットは、関数が作成したサムネイルを保存するバケットです。

Lambda関数を作成します。
この関数の働きは、画像を読み込んでサムネイルを作成することです。
この関数は1つ目のバケットの通知がトリガーとなって実行されます。

CloudFormationテンプレートファイル

上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。

awstut-dva/03/005 at main · awstut-an-r/awstut-dva
Contribute to awstut-an-r/awstut-dva development by creating an account on GitHub.

テンプレートファイルのポイント解説

S3バケット

バケット1

Resources: UploadBucket: Type: AWS::S3::Bucket Properties: AccessControl: Private BucketName: !Ref UploadBucketName NotificationConfiguration: LambdaConfigurations: - Event: "s3:ObjectCreated:*" Function: !Ref ThumbnailFunctionArn
Code language: YAML (yaml)

サムネイルの元となる画像を配置するバケットです。
NotificationConfigurationプロパティで通知設定を行います。
今回の構成では、通知先にLambda関数を指定しますので、LambdaConfigurationsプロパティを使用します。
画像がバケットに設置された際に、Lambda関数にイベント通知するため、Eventプロパティに「s3:ObjectCreated:*」を、Functionプロパティに後述の関数を指定します。

バケット2

Resources: ResizeBucket: Type: AWS::S3::Bucket Properties: AccessControl: Private BucketName: !Ref ResizeBucketName
Code language: YAML (yaml)

関数が生成したサムネイル画像を配置するバケットです。

特別な設定は行いません。

Lambda

関数

Resources: ThumbnailFunction: Type: AWS::Lambda::Function Properties: Architectures: - !Ref Architecture Code: ZipFile: | import boto3 import os import sys import uuid from urllib.parse import unquote_plus from PIL import Image import PIL.Image s3_client = boto3.client('s3') def resize_image(image_path, resized_path): with Image.open(image_path) as image: image.thumbnail(tuple(x / 2 for x in image.size)) image.save(resized_path) def lambda_handler(event, context): for record in event['Records']: bucket = record['s3']['bucket']['name'] key = unquote_plus(record['s3']['object']['key']) tmpkey = key.replace('/', '') download_path = '/tmp/{}{}'.format(uuid.uuid4(), tmpkey) upload_path = '/tmp/resized-{}'.format(tmpkey) s3_client.download_file(bucket, key, download_path) resize_image(download_path, upload_path) s3_client.upload_file(upload_path, '{}-resized'.format(bucket), key) FunctionName: !Sub "${Prefix}-ThumbnailFunction" Handler: !Ref Handler Layers: - !Ref LambdaLayer Runtime: !Ref Runtime Role: !GetAtt ThumbnailFunctionRole.Arn Timeout: !Ref Timeout
Code language: YAML (yaml)

Lambda関数で実行するコードをインライン形式で記載します。
詳細につきましては、以下のページをご確認ください。

実行するコードですが、以下のAWS公式ページに記載されているコードを使用します。

チュートリアル: Amazon S3 トリガーを使用してサムネイル画像を作成する - AWS Lambda
このチュートリアルでは、Lambda 関数を作成し、Amazon Simple Storage Service (Amazon S3) のトリガーを設定します。Amazon S3 は、S3 バケットにアップロードされる各画像ファイルの CreateThumbnail 関数を呼び出します。この関数は、ソース S3 バケッ...

コードの内容ですが、以下の流れです。

  • 受け取ったイベント通知から、通知元のバケット名や配置されたオブジェクト名を取得する。
  • S3バケットからオブジェクトをローカルストレージにダウンロードする。
  • ダウンロードしたオブジェクトをリサイズしてサムネイルを作成する。
  • サムネイルをバケットに配置する。

この関数用のIAMロールを確認します。

Resources: ThumbnailFunctionRole: Type: AWS::IAM::Role DeletionPolicy: Delete Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: - lambda.amazonaws.com ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: CreateThumbnailPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - s3:GetObject Resource: - !Sub "arn:aws:s3:::${UploadBucketName}/*" - Effect: Allow Action: - s3:PutObject Resource: - !Sub "arn:aws:s3:::${ResizeBucketName}/*"
Code language: YAML (yaml)

2つのバケットに対してのアクションを許可する内容です。
画像をアップロードするバケットに対しては、関数は画像をダウンロードしますので、「s3:GetObject」の権限を与えます。
サムネイルを配置するバケットに対しては、関数は画像をアップロードしますので、「s3:PutObject」の権限を与えます。

Lambdaレイヤー

Lambda関数がサムネイルを作成する過程で、Pillowパッケージを使用します。
外部パッケージは、Lambdaレイヤーを作成し、こちらにパッケージを含めることで、Lambda関数がクライアントモジュールをインポートすることができるようになります。
今回はCloudFormationカスタムリソースを使用することによって、このLambdaレイヤーの作成を自動的に実行します。
詳細については、以下のページをご確認ください。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。
スタックの作成および各スタックの確認方法については、以下のページをご確認ください。

各スタックのリソースを確認した結果、今回作成された主要リソースの情報は以下の通りです。

  • 画像アップロード用S3バケット:dva-03-005
  • サムネイル設置用S3バケット:dva-03-005-resized
  • サムネイル作成用Lambda関数:dva-03-005-ThumbnailFunction

AWS Management Consoleから各リソースを確認します。

まず画像アップロード用バケットを確認します。

Detail of S3 1.
Detail of S3 2.

イベント通知に関する設定があります。
オブジェクト作成に関する全てのイベントを対象として、後述のLambda関数を実行する内容です。

Lambda関数を確認します。

Detail of Lambda 1

関数が正常に作成されています。
AWS公式ページで紹介されているコードを実行します。

動作確認

準備が整いましたので、バケットに画像を配置します。
AWS Management Consoleから画像をバケットに配置します。

Detail of S3 3.

テスト用の画像として、今回の構成図をアップロードします。

Detail of S3 4.

アップロードが完了しました。

オブジェクトをアップロードすることによって、Lambda関数にイベント通知されたはずです。
関数の実行ログを確認します。

Detail of Lambda 2

関数が自動的に実行されています。

サムネイル用バケットを確認します。

Detail of S3 5.

画像が設置されています。
イベント通知によって、自動的にLambda関数が実行されて、サムネイル画像を作成し、このバケットに設置しています。

最後に作成されたサムネイルを確認します。

Resized Image.

確かにリサイズされています。

このようにS3イベント通知を使用することによって、任意のイベント発生時に、Lambda関数を実行することができます。

まとめ

S3バケットに画像がアップロードされると、そのイベント通知をトリガーとして、サムネイルを作成するLambda関数が実行される構成を確認しました。

タイトルとURLをコピーしました