/ #cdk #python 

CDK(Python)で複数stackでリソースを共有する

もくじ

cdkで複数stackを使い、こっちのstackで作ったリソースを別のstackで使いたい!

というシチュエーションがあったのですが、どうしようか悩んだ挙げ句1個の巨大なStackにしてしまった、という経験があったので「さて、どうやったらstackを分けられるのかな?」と実装してみました。

調べてて分かったことは、いくつか方法があるぽいですね。

今回の構成はこんな感じです👍

以前の記事で作ったlambda-trigger-s3-stackを再利用して、そのBucketにPUTするlambdaを作ろうと思います👍

前提

cdkのシリーズの続き。

公式のドキュメントはこのあたり、

https://docs.aws.amazon.com/cdk/latest/guide/stack_how_to_create_multiple_stacks.html

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

requirements.txt

今回は使うリソースは以前のstacklambda-trigger-s3-stackと同じなので、requirements.txtに追加する行はありません、詳細は過去記事を参照くださいませ🙇

以前のstackのstackファイルへの追記

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

      # ...省略
      self.bucket = bucket

__init__の末尾に作成したbucketをインスタンス変数に登録します。

今回のstackファイル

ほぼほぼいつもと一緒ですが、違う点は__init__の引数にput_bucket: aws_s3.Bucketを持っていることです。

ここに他で作ったS3Bucketのリソース情報を受け取って内部に反映させる感じですね👍

後はlambdaからS3にアクセスするために、環境変数へバケット名を入れている点ですかね

from aws_cdk import aws_lambda, aws_s3, core


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

        # lambda
        lambda_ = aws_lambda.Function(
            self,
            "SameResourceLambda",
            code=aws_lambda.Code.asset("lambdas/same_resource"),
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            handler="lambda_function.lambda_handler",
            environment={"PUT_BUCKET_NAME": put_bucket.bucket_name},
        )

        # lambdaの権限
        put_bucket.grant_write(lambda_)

lambdaの実装

いつものおまけです(笑)

import json
import os
from datetime import datetime

import boto3

s3 = boto3.resource("s3")


def lambda_handler(event, context):

    bucket_name = os.getenv("PUT_BUCKET_NAME")
    key = f"{datetime.now()}.json"

    object = s3.Object(bucket_name, key)
    object.put(Body=json.dumps(event))

    return {}

エントリーポイントへ修正と追記

まず修正点ですが、LambdaTriggerS3Stackのインスタンスを変数で取得できるようにします。

次に追記分は今回のスタックを追加し、引数でbucketを渡します。

最終的なコードはこんな感じ(↓)

...省略...
from stacks.same_resource import SameResourceStack
...省略...
lambda_trigger_s3_stack = LambdaTriggerS3Stack(app, "lambda-trigger-s3-stack", env=env)
SameResourceStack(app, "same-resources-stack", put_bucket=lambda_trigger_s3_stack.bucket, env=env)
...省略...

デプロイ🚀

GoGo-🎉

$ cdk deploy lambda-trigger-s3-stack
$ cdk deploy same-resources-stack

確認

今回作ったlambdaの名前を取得します。

コンソールから取得するなり、こんな(↓)感じで取得するなりとってきます。

$ aws lambda list-functions | grep same-resources-stack

今回はこんな名前same-resources-stack-SameResourceLambda6084D48C-A27UUTX5LQMMでした😅

そして、もう一つ。S3のBucket名を取得します。こんな(↓)感じ

$ aws s3 ls | grep lambda-trigger-s3-stack

名前はlambda-trigger-s3-stack-lambdatriggers3bucket8c39-s20rkcnz27i5でした。

可読性向上のため変数に放り込みます。

$ LAMBDA_NAME=same-resources-stack-SameResourceLambda6084D48C-A27UUTX5LQMM
$ BUCKET_NAME=lambda-trigger-s3-stack-lambdatriggers3bucket8c39-s20rkcnz27i5

Lambdaを動かしてみる。

$ aws lambda invoke --function-name $LAMBDA_NAME --payload '{"hoge_key": "hogehoge_data"}' response.json
{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST"
}

# 一応レスポンスの確認
$ cat response.json
{}

Bucketにobjectが入ったことを確認する。

$ aws s3 ls s3://$BUCKET_NAME
2020-11-17 22:53:25         29 2020-11-17 13:53:23.850327.json

なにやら2020-11-17 13:53:23.850327.jsonというobjectがいますね😉

そして、、、あ、やらかしましたね私😰

key名にスペース入ってる。。。のがちょっとやな感じ、、、ダブルクォーテーション入れとけばいいかな🤔

$ aws s3 cp "s3://$BUCKET_NAME/2020-11-17 13:53:23.850327.json" -
{"hoge_key": "hogehoge_data"}

まぁとりあえず、Lambdaで入れたeventの内容がobjectとしてきちんと入ったのが確認できました👍

destroy💣

今回作ったstackを削除しておきましょう😉

まずバケットが空でないと削除できないので空にします。

$ aws s3 rm s3://$BUCKET_NAME --recursive

# 空っぽになったことを確認する
$ aws s3 ls s3://$BUCKET_NAME

複数stackをまとめて削除

$ cdk destroy --all

まとめ

cdkで複数stackを使い片方のstackで他方のリソースを使うということを実装してみました。

そしてcdk上から動作の確認をしました👍

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

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

Author

Sisii

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