/ #aws #cdk 

CDK(Python)でS3をトリガーにしてLambdaを発火する

もくじ

S3のバケットにObjectが入ったのをトリガーにしてLambdaを発火するー、

をPythonのCDKで実装してみます👍

アーキテクチャを描くとこんな感じです。

アーキテクチャ

久々にブログにアーキテクチャを張り付けた😁これ描くの好き

そして初めにことわって置きたいのですが、cdkには上記をイメージして実装します。

実際にCDKから出力されるテンプレートは若干違うモノになります😅

前提

過去記事の分岐

では 作っていきましょう👻

といってもほぼほぼコードのサンプルになりますが😅

requirements.txt

使うリソースはlambdaとS3とlambdaのトリガーなので必要なのはcoreを除いて3つです。

aws-cdk.core==1.72.0

aws-cdk.aws_s3==1.72.0
aws-cdk.aws-lambda==1.72.0
aws_cdk.aws_lambda_event_sources==1.72.0

lambdaの実装

おまけですがlambdaはこんな感じで作っておきます

import json
import boto3

s3 = boto3.resource("s3")


def lambda_handler(event, context):

    s3_record = event["Records"][0]["s3"]
    object = s3.Object(s3_record["bucket"]["name"], s3_record["object"]["key"])
    file_body = object.get()["Body"].read()

    print(file_body)

    return {}

Stackの実装

from aws_cdk import aws_lambda, aws_s3, core
from aws_cdk.aws_lambda_event_sources import S3EventSource


class LambdaTriggerS3Stack(core.Stack):
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # S3
        bucket = aws_s3.Bucket(
            self,
            "LambdaTriggerS3Bucket",
            removal_policy=core.RemovalPolicy.DESTROY,  # Stack削除と同時にバケットを削除する
        )

        # lambda
        common_lambda_params = dict(
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            handler="lambda_function.lambda_handler",
            timeout=core.Duration.seconds(10),
            memory_size=128,
        )
        lambda_ = aws_lambda.Function(
            self,
            "LambdaTriggerS3Lambda",
            code=aws_lambda.Code.asset("lambdas/lambda_trigger_s3"),
            **common_lambda_params,
        )

        # lambdaにtriggerを付与
        lambda_.add_event_source(
            S3EventSource(
                bucket,
                events=[aws_s3.EventType.OBJECT_CREATED_PUT],
                # filterを設定する場合は、下記のコメントアウトを外す
                # filters=[aws_s3.NotificationKeyFilter(prefix="カスタムプレフィックス/", suffix="拡張子")],
            )
        )

        # lambdaの権限
        bucket.grant_read(lambda_)

エントリーポイントに追記

app.pyに下記を追記します。

...省略...
from stacks.lambda_trigger_s3_stack import LambdaTriggerS3Stack
...省略...
LambdaTriggerS3Stack(app, "lambda-trigger-s3-stack", env=env)
...省略...

deploy

$ cdk deploy lambda-trigger-s3-stack

アップロードしてみる

バケット名を指定しなかったのでとんでもない名前(バケット名:lambda-trigger-s3-stack-lambdatriggers3bucket8c39-s20rkcnz27i5)になりました(笑)

バケット名をコンソールや$ aws s3 ls | grep lambda-trigger-s3-stackあたりで調べて、下記を参考にitemをアップロードしてみてください

$ echo hogehoge > item.txt

$ aws s3 cp item.txt s3://lambda-trigger-s3-stack-lambdatriggers3bucket8c39-s20rkcnz27i5/

CloudWatchのコンソールでログを確認すると、objectをきちんと取得して出力できていることが確認できました。

START RequestId: 850b642c-6c3e-43dd-8bce-2456b74eb617 Version: $LATEST
b'hogehoge\n'
END RequestId: 850b642c-6c3e-43dd-8bce-2456b74eb617

そして余談ですが、じつはlambdaがもう一つ自動でデプロイされていて、それがこんな感じ(↓)で発生したイベントのログを残してます。このへんが一番初めにことわったアーキテクチャとの違いです。

{
    "RequestType": "Create",
    ...省略
                    "Events": [
                        "s3:ObjectCreated:Put"
                    ],
    ...省略
}

まとめ

今回はcdkを使って、S3バケットにデータが入ったこと(ObjectCreated:Put)をトリガーにlambdaを発火するサンプルを作り、動作の確認をしました👍

今回のリポジトリはこちら

https://github.com/sisi100/cdk-my-template/tree/20201109.0

Author

Sisii

インフラが好きなエンジニアぶってるなにか