S3をトリガーとしてLambdaでサムネイルを自動生成する

スポンサーリンク
ハンズオン
スポンサーリンク

はじめに

今回はS3のイベントをトリガーとしてLambdaを起動させるハンズオンを紹介します。
S3のイベントをトリガーにLambdaを起動するといったことは実例でも認定試験の問題としてもよくあるケースなので、
このハンズオンを通して習得しましょう。
今回のハンズオンでは、S3にアップロードされた画像をトリガーにLambda関数を起動し、サムネイルを自動生成するフローを構築します。

この記事で得られるスキル:

  • S3イベントの設定
  • Lambda関数の作成とS3との連携
  • サーバーレスアーキテクチャの理解
  • 自動化された画像処理の実装

1. 環境構成

以下の構成でハンズオンを実施します。

2. S3バケットの作成

以下のS3バケットを作成します。※「XXXXXXXX」は任意の文字列

  • オリジナルの画像ファイルの格納先;input-images-XXXXXXXX
  • サムネイルの画像ファイルの格納先;output-thumbnails-XXXXXXXX

AWS管理コンソールで「S3」を検索し、S3コンソールに移動します。
「バケットを作成」ボタンをクリックしてバケットを作成します。

上記のバケット名を指定してバケットを作成を選択してください。他の設定はそのままで構いません。

3. Lambda関数の作成

オリジナルの画像ファイルが格納されたときに動作させるLambda関数を作成します。
AWS管理コンソールで「Lambda」を検索し、Lambdaコンソールに移動します。
「関数を作成」をクリックし、次の設定を行います。

  • 関数名: ThumbnailGenerator
  • ランタイム: Python 3.12
    「関数を作成」をクリックしてLambda関数を作成します。

4. Lambdaコードの作成

Lambdaコンソールの関数エディタで、以下のPythonコードを貼り付けます。

import boto3
from PIL import Image
import io

s3 = boto3.client('s3')

def lambda_handler(event, context):
    # S3イベント情報からバケット名とファイル名を取得
    source_bucket = event['Records'][0]['s3']['bucket']['name']
    key = event['Records'][0]['s3']['object']['key']
    destination_bucket = 'output-thumbnails-XXXXXXXX' ## サムネイルの画像ファイルの格納先のS3バケット

    try:
        # 画像を取得
        response = s3.get_object(Bucket=source_bucket, Key=key)
        image = Image.open(io.BytesIO(response['Body'].read()))

        # サムネイルを生成
        thumbnail_size = (128, 128)
        image.thumbnail(thumbnail_size)

        # 画像をバイトストリームに変換
        buffer = io.BytesIO()
        image.save(buffer, 'JPEG')
        buffer.seek(0)

        # サムネイルを別のバケットに保存
        s3.put_object(
            Bucket=destination_bucket,
            Key=f'thumbnail-{key}',
            Body=buffer,
            ContentType='image/jpeg'
        )

        return {
            'statusCode': 200,
            'body': 'Thumbnail generated successfully!'
        }

    except Exception as e:
        print(f"Error processing file {key} from bucket {source_bucket}: {str(e)}")
        raise e

コードを貼り付けたら、「デプロイ」をクリックしてLambda関数をデプロイします。

5. レイヤーの指定

コードには外部ライブラリが含まれます。https://api.klayers.cloud/api/v2/p3.12/layers/latest/ap-northeast-1/htmlで公開されている。自分でカスタムレイヤーを作成する方法はありますが、今回は公開されているレイヤーを使ってみます。

「コード」タブを選択し、画面下部の「レイヤー」セクションから「レイヤーの追加」を選択します。

レイヤーを追加の画面で、レイヤーソースを「ARNを指定」を選択します。
ARNに「arn:aws:lambda:ap-northeast-1:770693421928:layer:Klayers-p312-pillow:1」と入力し、「検証」を選択してください。
ランタイムと互換性があるアーキテクチャが表示されるので、確認して「追加」を選択してください。

6. LambdaのIAMロールの設定

デフォルトで紐づいているIAMロールにそれぞれのS3にアクセスできるようポリシーを作成してアタッチします。
「ThumbnailGenerator」のLambda関数の画面で、「設定」タブ>左メニューから「一般設定」>「編集」を選択してください。

画面下部の「 ThumbnailGenerator-role-******** ロールを表示」を選択してください。

許可ポリシーから「許可の追加」>「インラインポリシーのアタッチ」を選択します。

ポリシーエディタで「JSON」を選択し以下を入力してください。「XXXXXXXX」の部分は作成したS3バケット名に合わせてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::input-images-バケット名/images/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::output-thumbnails-バケット名/thumbnail-*"
        }
    ]
}

ポリシー名は「ThumbnailGeneratorS3AccessPolicy」とし「ポリシーを生成」を選択してください。

7. S3イベント通知の設定

input-images-XXXXXXXXの詳細画面に移動し、「プロパティ」タブを選択します。
「イベント通知」セクションまでスクロールし、「イベント通知を追加」をクリックします。
以下のように設定し、「変更の保存」を選択します。

  • イベント名:TriggerImageUpload
  • プレフィックス:images/
  • サフィックス:指定なし(拡張子など指定があれば、.png、.jpgなどを設定してください。)
  • イベントタイプ: PUT
  • 送信先:Lambda関数
  • Lambda関数:ThumbnailGenerator

8. 動作確認

  • input-images-XXXXXXXXの「images/」フォルダを作成し、「images/」フォルダに任意の画像ファイルをアップロードします。試しに以下の画像をアップロードします。

  • output-thumbnails-XXXXXXXXにサムネイルが生成されていることを確認します。
  • ダウンロードしてサイズを確認してみると、画像サイズが小さくなっています。

9. まとめ

このハンズオンでは、S3をトリガーにLambdaを起動し、画像のサムネイルを自動生成する処理を実装しました。
S3のイベントを活用してLambda関数を実行する仕組みが理解できたかと思います。
このハンズオンが、皆さんのスキルアップやAWS認定資格の取得に役立つことを願っています。
さらに応用として、以下のような実装が可能です。

  • 異なる画像サイズの生成やフォーマットの変換、画像の圧縮
  • ライフサイクルポリシーを活用した保存期間の設定や自動削除

ぜひ、今回の内容をベースに、より複雑な処理や新しいアイデアに挑戦してみてください。

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