AWS Lambdaの構築をする際、監視用のリソースも併せて構築できてしまえば都合がいいと思ったため、以下のリソースを作成するCDK Constructを作成してみました。
なお、今回はCDKはV.2、言語はPythonとなります。
- Lambda関数
- Lambda関数のThrottle Metricsを監視するCloudWatch Alarm
- Lambda関数のLogGroupのERRORを監視するSubscription Filter
※AlarmやSubscription filterから先のSNS TopicやLambda関数に関しては引数として受け取る形にしています。
※ここでは、LogGroupのエラー内容をメール本文に記載する目的でSubscription filterの先をLambdaとしています。
全コードはGithubを参照してください。
Githubはここ
前提条件
- AWS CDK v.2 がインストールされていること
- Python 3.x がインストールされていること
- AWSアカウントがあり、AWS CLIが設定されていること
※Cloud9を使うとこの辺りがPassできるため、Cloud9を使って今回の記事の内容は作成しています。
構築手順
1.CDKアプリの初期化
先ずはCDKアプリの初期化を行います。
$ mkdir cdk-lambda-with-monitoring
$ cd cdk-lambda-with-monitoring
$ cdk init --language python
2. 必要なパッケージをインストール
ここでは、CDKアプリを初期化した際に作成された.venvを有効化しています。
$ source .venv/bin/activate
$ pip install -r requirements.txt
3. Constructの作成
下のコードで、Lambda関数とSubscription filter、Alarmを作成しています。
import os
from aws_cdk import (
Duration,
Stack,
aws_cloudwatch as cloudwatch,
aws_cloudwatch_actions as cloudwatch_actions,
aws_lambda as lambda_,
aws_logs as logs,
aws_logs_destinations as logs_destinations,
)
from constructs import Construct
class LambdaWithMonitoring(Construct):
def __init__(
self, scope: Construct, construct_id: str, function_props,
operation_topic, publish_message_function, **kwargs) -> None:
"""
Initialize method
parameters
----------
function_props: dict
Lambda関数のプロパティ
sns_topic: aws_sns.Topic
Alarmの内容を通知するTopic
publish_message_function: lambda.Function
lambdaのLogGroupのError通知を成形しSNS Topicに渡す関数
"""
super().__init__(scope, construct_id, **kwargs)
# Create lambda function
lambda_function = lambda_.Function(
self, f'{construct_id}LambdaFunction', **function_props
)
# Throttle error alarm
throttles_alarm = cloudwatch.Alarm(
self, f'{construct_id}ThrottlesAlarm',
metric=cloudwatch.Metric(
metric_name='Throttles',
namespace='AWS/Lambda',
dimensions_map={'FunctionName': lambda_function.function_name},
period=Duration.minutes(1),
statistic='Sum',
),
evaluation_periods=1,
threshold=0,
comparison_operator \
=cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
)
throttles_alarm.add_alarm_action(
cloudwatch_actions.SnsAction(operation_topic)
)
# LogGroup error alarm
lambda_function.log_group.add_subscription_filter(
f'{construct_id}SubscriptionFilter',
destination=logs_destinations.LambdaDestination(
publish_message_function
),
filter_pattern=logs.FilterPattern.any_term('ERROR'),
)
4.実際スタックから呼出してみる
下のスタックの定義の中では、通知用のSNS TopicとLambdaを引数として自作Constructに渡しています。
また、自作Constructを利用して二つのLambda+監視リソースを作成しています。
なお、Lambda関数のLogGroupのエラー内容をメールで通知する方法は以下を参照してください。
AWS CDK(ver.2) pythonを使って、Lambdaのエラー内容をメールで通知してみた
import os
from aws_cdk import (
Duration,
Stack,
aws_lambda as lambda_,
aws_sns as sns,
aws_sns_subscriptions as subscriptions,
)
from constructs import Construct
from cdk_lambda_with_monitoring.lambda_with_monitoring import LambdaWithMonitoring
class CdkLambdaWithMonitoringStack(Stack):
def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# SNS Topic for notification
operation_topic = sns.Topic(self, 'OperationTopic')
subscription = operation_topic.add_subscription(
subscriptions.EmailSubscription('shinya_takaramoto@ulvac.com')
)
# lambdaのLogGroupのError通知を成形しSNS Topicに渡す関数
publish_message_function = lambda_.Function(
self,
'PublishMessageFunction',
runtime=lambda_.Runtime.PYTHON_3_9,
handler='lambda_function.lambda_handler',
code=lambda_.Code.from_asset(
os.path.join('lambda', 'publish_message_function')
),
environment={
'OPERATION_TOPIC_ARN': operation_topic.topic_arn
},
)
operation_topic.grant_publish(publish_message_function)
# First lambda function with monitoring
function_props_1 = {
'code': lambda_.Code.from_asset(os.path.join('lambda', 'func1')),
'handler': 'lambda_function.lambda_handler',
'runtime': lambda_.Runtime.PYTHON_3_9,
'function_name': 'test-lambda-func1',
'memory_size': 128,
'timeout': Duration.seconds(3)
}
lambda_with_monitoring_1 = LambdaWithMonitoring(
self, 'LambdaWithMonitoring1', function_props_1, operation_topic,
publish_message_function
)
# Second lambda function with monitoring
function_props_2 = {
'code': lambda_.Code.from_asset(os.path.join('lambda', 'func2')),
'handler': 'lambda_function.lambda_handler',
'runtime': lambda_.Runtime.PYTHON_3_8,
'function_name': 'test-lambda-func2',
'memory_size': 128,
'timeout': Duration.seconds(10)
}
lambda_with_monitoring_2 = LambdaWithMonitoring(
self, 'LambdaWithMonitoring2', function_props_2, operation_topic,
publish_message_function
)
デプロイが完了すると、Lambda関数と関連した監視リソースが2つ作成されます。
まとめ
今回は、Lambda+監視用のリソースをまとめて作成する自作のCDK Constructをご紹介しました。プロジェクトの中で再利用性を全く検討していなかった反省点を活かして、少し再利用性の高そうなものを作ってみた次第です。
どなたかの参考となれば幸いです。