1. はじめに
Lambda ✕ ApiGatewayでAPIを構築することが良くあります。
この構成をAWS SAM や CloudForamtionで構築することがありましたが、APIが数十個構築する必要があるとLambdaごとにテンプレートを作成するのが大変になります。
また、手作業でテンプレートをAWS SAM に記載すると追加漏れや修正漏れが発生することが、見受けられました。
こういった場面で CDK を利用するとスマートに構築することができます。
2. やりたいこと
- Lambdaを複数定義する。
- API GatewayとLambdaを紐付ける。
- IAM を別スタックに分離する。
- CLoudWatch のロググループを明示的に作成する。
前提
- AWS CLIインストール済みであること
- Python3.13インストール済みであること
- AWS CDKインストール済みであること
3. 構成
3.1. スタックの構成
AppStack IamStack
↓ ↓
[Lambda] [IAM Role]
↓
[LogGroup]
↓
[API Gateway]
3.2. ディレクトリ構造
.
└── cdk_test
├── app.py
├── cdk.json
├── functions.json
├── lambda
│ ├── lambda_1
│ │ └── handler.py
│ ├── lambda_2
│ │ └── handler.py
│ └── handler.py
├── requirements-dev.txt
├── requirements.txt
├── source.bat
├── stacks
│ ├── __init__.py
│ ├── app_stack.py
│ └── iam_stack.py
4. Lambdaの定義をjsonで管理するメリット
- Lambdaの追加や設定の変更時にコードを修正する必要がなくなる。
5. 実装コード紹介
5.1 functions.json
Lambdaを追加する際はこのjsonファイルに記述する。
[
{ "name": "lambda_1", "expose_api": true },
{ "name": "lambda_2", "expose_api": false }
]
5.2 IAMスタック
Lambdaの実行ロール用のスタックを生成する。
from aws_cdk import Stack
from aws_cdk.aws_iam import Role, ServicePrincipal, PolicyStatement
from constructs import Construct
class IamStack(Stack):
def __init__(self, scope: Construct, id: str, **kwargs):
super().__init__(scope, id, **kwargs)
self.lambda_execution_role = Role(
self, "LambdaExecutionRole",
assumed_by=ServicePrincipal("lambda.amazonaws.com")
)
self.lambda_execution_role.add_to_policy(PolicyStatement(
actions=[
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
resources=["*"]
))
5.3 AppStack
AppStackでLambda、ロググループ、ApiGatewayの生成を行う。
from aws_cdk import Stack
from aws_cdk.aws_lambda import Function, Runtime, Code
from aws_cdk.aws_apigateway import RestApi, LambdaIntegration
from aws_cdk.aws_logs import LogGroup, RetentionDays
from constructs import Construct
import os
import json
class AppStack(Stack):
def __init__(self, scope: Construct, id: str, lambda_role, **kwargs):
super().__init__(scope, id, **kwargs)
api = RestApi(self, "MyApi")
functions = self._load_functions_from_file("functions.json")
for function in functions:
log_group = LogGroup(
self, f"{function["name"]}LogGroup",
log_group_name=f"/aws/lambda/{function["name"]}",
retention=RetentionDays.ONE_WEEK
)
lambda_fn = Function(
self, f"{function["name"].capitalize()}Lambda",
function_name=function["name"],
runtime=Runtime.PYTHON_3_11,
handler="handler.lambda_handler",
code=Code.from_asset(f"lambda/{function["name"]}"),
role=lambda_role,
log_group=log_group
)
api.root.add_resource(function["name"]).add_method("GET", LambdaIntegration(lambda_fn))
def _load_functions_from_file(self, file_path):
with open(file_path, "r") as f:
return json.load(f)
5.4 app.py
app.pyでIamStackとAppStackをインスタンス化する。 IamStackで生成したLambda実行ロールをAppStackに渡してLambdaに紐付ける
from aws_cdk import App
from stacks.iam_stack import IamStack
from stacks.app_stack import AppStack
app = App()
iam_stack = IamStack(app, "IamStack")
AppStack(app, "AppStack", lambda_role=iam_stack.lambda_execution_role)
app.synth()
6. さいごに
このようにCDKを利用すれば、複数のLambdaを楽に構築することが可能になります。
Lambda, ApiGatewayやCloudWatch ロググループの作成やアラートは大量のリソースを一括で作成することが多くあります。
そういった要件にはCDKを利用するには力を発揮すると思います。