この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので十分ご注意ください。
はじめに
普段DynamoDBをあまり使用しないので、CloudFormationの練習がてら構築していきたいと思います。
学習に利用した教本は、AWS Lambda実践ガイド 第2版 (impress top gear) 著:大澤文孝
を利用しています。
GUI及び、SAMによる構築はありましたが、CFnでの構築はなかったので、書籍のエッセンスを使いつつ、自分なりに少しアーキテクトを変更して構築をしてみました。
構成図
ハンズオン
構築のながれ
1.S3作成:SNSメール雛形保存
2.SNS作成:メール通知のため構築
3.SQS作成:LambdaとLambdaを疎結合で構築
4.Lambda(sendmail)作成:メール未送信ユーザにメール通知の構築
5.DynamoDB作成:ユーザ名/アドレス/二重配信チェック DBの構築
6.Lambda(sendqueue)作成:DynamoDBに該当カラムを持つ場合 SQSを発行する構築
7.EventBridge作成:CronでLambda(sendqueue)とトリガーを構築
1.S3作成:SNSメール雛形保存
1.1.CFn で S3 構築
・SNS
で送信する通知内容を保存するためのバケットを作成
AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation to create S3 Bucket
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "S3 Configuration"
Parameters:
- S3BucketName
- AccessControl
- BlockPublicAcls
- BlockPublicPolicy
- IgnorePublicAcls
- RestrictPublicBuckets
- ExpirationInDays
- EventBridgeConfiguration
- Prefix
- TagsName
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
S3BucketName:
Type: String
Default: "cfn-s3-20230102-inamura"
Description: Type of this BacketName.
VersioningConfiguration:
Type: String
Default: "Enabled"
Description: VersioningConfiguration.
AccessControl:
Type: String
Description: AccessControl.
Default: "Private"
AllowedValues: [ "Private", "PublicRead", "PublicReadWrite", "AuthenticatedRead", "LogDeliveryWrite", "BucketOwnerRead", "BucketOwnerFullControl", "AwsExecRead" ]
BlockPublicAcls:
Type: String
Description: BlockPublicAcls.
Default: "True"
AllowedValues: [ "True", "False" ]
BlockPublicPolicy:
Type: String
Description: BlockPublicPolicy.
Default: "True"
AllowedValues: [ "True", "False" ]
IgnorePublicAcls:
Type: String
Description: IgnorePublicAcls.
Default: "True"
AllowedValues: [ "True", "False" ]
RestrictPublicBuckets:
Type: String
Description: RestrictPublicBuckets.
Default: "True"
AllowedValues: [ "True", "False" ]
ExpirationInDays:
Type: String
Description: Lifecycle Days.
Default: "7"
TagsName:
Type: String
Description: UserName
Default: "inamura"
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref S3BucketName
VersioningConfiguration:
Status: !Ref VersioningConfiguration
AccessControl: !Ref AccessControl
PublicAccessBlockConfiguration:
BlockPublicAcls: !Ref BlockPublicAcls
BlockPublicPolicy: !Ref BlockPublicPolicy
IgnorePublicAcls: !Ref IgnorePublicAcls
RestrictPublicBuckets: !Ref RestrictPublicBuckets
LifecycleConfiguration:
Rules:
- Id: LifeCycleRule
Status: Enabled
ExpirationInDays: !Ref ExpirationInDays
# #イベント通知 Lambda構築後コメントアウト解除
# NotificationConfiguration:
# LambdaConfigurations:
# - Event: "s3:ObjectCreated:*"
# Function: !ImportValue cfn-lmd-sendqueue-inamura-arn
# #ここまで
Tags:
- Key: "User"
Value: !Ref TagsName
# ------------------------------------------------------------#
# Outputs
# ------------------------------------------------------------#
Outputs:
S3BucketName:
Value: !Ref S3Bucket
Export:
Name: cfn-s3-BucketName
1.2.S3 に SNSメール雛形保存
template-mail.txt
としてSNS
で送信する通知内容を、S3へ保存する
メール配信:テスト
【テスト内容】新規ユーザが登録されました
コンソール画面からだと下記のような状態となる
2.SNS作成:メール通知のため構築
2.1 SNSを構築する
・EventBridge
をトリガーにして、DynamoDB
に登録したユーザにメール通知がされていない場合に、こちらのSNS
を利用してメールが通知される
・TopicPolicy
部分は、検証のため制限していません。
AWSTemplateFormatVersion: "2010-09-09"
Description: SNS Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "SNS Configuration"
Parameters:
- TopicName
- Endpoint
ParameterLabels:
TopicName:
default: "TopicName"
Endpoint:
default: "MailAddress"
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
TopicName:
Type: String
Default: "cfn-sns-topic-inamura"
Endpoint:
Type: String
Default: "XXXXXXXXXX@gmail.com"
TagsValueUserName:
Type: String
Default: "inamura"
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
SNSTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: !Ref TopicName
Subscription:
- Endpoint: !Ref Endpoint
Protocol: email
Tags:
- Key: "User"
Value: !Ref TagsValueUserName
TopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref SNSTopic
PolicyDocument:
Id: !Ref SNSTopic
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS: "*"
Action: SNS:Publish
Resource: !Ref SNSTopic
# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
SNSArn:
Value: !Ref SNSTopic
Export:
Name: !Sub "${TopicName}-arn"
SNSTopicName:
Value: !Ref TopicName
Export:
Name: !Ref TopicName
2.2 上記設定後に、SNSから送られてきたメールのサブスクリプションを押下する
①送られてきたメールの赤枠部分をクリックする
②画面が遷移して下記画面が表示されると、サブスクリプションが開始される
※上記青枠部分をクリックすると、サブスクリプションが解除される
3.SQS作成:LambdaとLambdaを疎結合で構築
・2つの処理をするLambda
の間を疎結合するために構築
・今回はDynamoDBとLambda側で二重配信チェックを含めたため、標準キューを利用
・可視性タイムアウト
をLambda
のタイムアウトを10秒としているため30秒と設定
・10分ごとにCronされるため保持期間を9分と設定
・2回通知を失敗すると、DLQ
へ移行し、DLQ
のメッセージ保持期間は1時間と設定
AWSTemplateFormatVersion: '2010-09-09'
Description: SQS Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "SQS Configuration"
Parameters:
- QueueName
- DeadLetterQueueName
- TagsValue
ParameterLabels:
QueueName:
default: "QueueName"
DeadLetterQueueName:
default: "DeadLetterQueueName"
TagsValue:
default: "TagsValue"
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
QueueName:
Type: String
Default: "cfn-sqs-inamura"
DeadLetterQueueName:
Type: String
Default: "cfn-dlq-inamura"
TagsValue:
Type: String
Default: "inamura"
# ------------------------------------------------------------#
# SQS
# ------------------------------------------------------------#
Resources:
NotifySQS:
Type: AWS::SQS::Queue
Properties:
QueueName: !Ref QueueName
VisibilityTimeout: 30
MessageRetentionPeriod: 540
RedrivePolicy:
deadLetterTargetArn: !GetAtt DeadLetterQueue.Arn
maxReceiveCount: 2
Tags:
- Key: "User"
Value: !Ref TagsValue
DeadLetterQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: !Ref DeadLetterQueueName
MessageRetentionPeriod: 3600
Tags:
- Key: "User"
Value: !Ref TagsValue
# ------------------------------------------------------------#
# SQS QueuePolicy
# ------------------------------------------------------------#
SQSPolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref NotifySQS
PolicyDocument:
Statement:
-
Action:
- "SQS:*"
Effect: "Allow"
Resource: !GetAtt NotifySQS.Arn
Principal:
AWS:
- "*"
-
Action:
- "SQS:*"
Effect: "Allow"
Resource: !GetAtt DeadLetterQueue.Arn
Principal:
AWS:
- "*"
# ------------------------------------------------------------#
# Output Parameters
# ------------------------------------------------------------#
Outputs:
NotifySQS:
Value: !GetAtt NotifySQS.QueueName
Export:
Name: !Sub "${QueueName}-queuename"
QueueArn:
Value: !GetAtt NotifySQS.Arn
Export:
Name: !Sub "${QueueName}-queuearn"
DeadLetterQueue:
Value: !GetAtt DeadLetterQueue.QueueName
Export:
Name: !Sub "${DeadLetterQueueName}-queuename"
DeadLetterQueueArn:
Value: !GetAtt DeadLetterQueue.Arn
Export:
Name: !Sub "${DeadLetterQueueName}-queuearn"
4.Lambda(sendmail)作成:メール未送信ユーザにメール通知の構築
・SQS
からメッセージを取得
・S3
に保存しているtemplate-mail.txt
より0行目
と2行目
を取得してメールで必要な変数を取得する
・DynamoDB
のsend
を1
にupdate
する。ただしReturnする値はアップデート前のものとすることで、既に送信したのか?していないのか?を判定
・上記判定をしてupdate
する前の値が0
であれば送っていないことになるのでSNS
でメール通知する
・メール通知したのでカラムnotsend
を1
にすることで、次回の判定から除かれるように更新
※ IAM部分のアカウトIDは XXXXXXXXXXXX
となっていますので、自身のアカウントIDを利用ください
AWSTemplateFormatVersion: '2010-09-09'
Description:
Lambda Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Lambda Configuration"
Parameters:
- FunctionName
- Description
- Handler
- MemorySize
- Runtime
- Timeout
- TagsName
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
FunctionName:
Type: String
Default: "cfn-lmd-sendmail-inamura"
Description:
Type: String
Default: "cfn-lmd-sendmail-inamura"
Handler:
Type: String
Default: "index.lambda_handler"
MemorySize:
Type: String
Default: "128"
Runtime:
Type: String
Default: "python3.9"
Timeout:
Type: String
Default: "10"
TagsName:
Type: String
Description: UserName
Default: "inamura"
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------#
Lambda:
Type: 'AWS::Lambda::Function'
Properties:
Code:
ZipFile: |
import boto3
import json
import os
import datetime
sqs = boto3.resource('sqs')
s3 = boto3.resource('s3')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('mailaddress')
sns = boto3.client('sns')
snsarn = os.environ['SNSARN']
def lambda_handler(event, context):
#SQSからメッセージ取得
for rec in event['Records']:
email = rec['body']
bucket = rec['messageAttributes']['bucket']['stringValue']
template = rec['messageAttributes']['template']['stringValue']
username = rec['messageAttributes']['username']['stringValue']
#S3メールテンプレートから本文生成
obj = s3.Object(bucket, template)
r = obj.get()
maildata = r['Body'].read().decode('utf-8')
data = maildata.split("\n", 3)
subject = data[0]
body = data[2]
#2重通知防止の仕組み
#DynamoDB sendするので1をUpdate ただしReturnでUpdate前を返す
r = table.update_item(
Key = {
'email' : email
},
UpdateExpression = "set send=:val",
ExpressionAttributeValues = {
':val' : 1
},
ReturnValues = 'UPDATED_OLD'
)
#条件分岐 未送信(Updateする前の UPDATED_OLD が 0) の場合SNS送信
if r['Attributes']['send'] == 0:
date = datetime.datetime.now()
d = date.strftime('%Y%m%d %H:%M:%S')
params = {
'TopicArn': snsarn,
'Subject': subject + str(d),
'Message': body
}
sns.publish(**params)
#DynamoDB sendしたので、notsendを1にUpdate
r =table.update_item(
Key = {
'email' : email
},
UpdateExpression = "set notsend=:val",
ExpressionAttributeValues = {
':val' : 1
}
)
else:
print("Resend Skip")
Description: !Ref Description
FunctionName: !Ref FunctionName
Handler: !Ref Handler
MemorySize: !Ref MemorySize
Runtime: !Ref Runtime
Timeout: !Ref Timeout
Role: !GetAtt LambdaRole.Arn
Environment:
Variables:
TZ: "Asia/Tokyo"
SNSARN: !ImportValue cfn-sns-topic-inamura-arn
Tags:
- Key: "User"
Value: !Ref TagsName
DeadLetterConfig:
TargetArn: !ImportValue cfn-dlq-inamura-queuearn
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${FunctionName}-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "sts:AssumeRole"
Principal:
Service: lambda.amazonaws.com
Policies:
- PolicyName: !Sub "${FunctionName}-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "logs:CreateLogGroup"
Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
- Effect: "Allow"
Action:
- "sqs:*"
Resource: "arn:aws:sqs:ap-northeast-1:XXXXXXXXXXXX:*"
- Effect: "Allow"
Action:
- "s3:*"
Resource: "*"
- Effect: "Allow"
Action:
- "dynamodb:*"
Resource: "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:*"
- Effect: "Allow"
Action:
- "sns:Publish"
Resource: "*"
EventSourceMapping:
Type: AWS::Lambda::EventSourceMapping
Properties:
Enabled: true
EventSourceArn: !ImportValue cfn-sqs-inamura-queuearn
FunctionName: !GetAtt Lambda.Arn
BatchSize: 10
# ------------------------------------------------------------#
# Output Parameters
#------------------------------------------------------------#
Outputs:
LambdaArn:
Value: !GetAtt Lambda.Arn
Export:
Name: !Sub "${FunctionName}-arn"
LambdaName:
Value: !Ref FunctionName
Export:
Name: !Sub "${FunctionName}-name"
5.DynamoDB作成:ユーザ名/アドレス/二重配信チェック DBの構築
5.1.CFnでDynamoDBを構築
AWSTemplateFormatVersion: '2010-09-09'
Description:
DynamoDB Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "DynamoDB Configuration"
Parameters:
- TableName
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
TableName:
Type: String
Default: "mailaddress"
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
DynamoDB:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: !Ref TableName
AttributeDefinitions:
- AttributeName: email
AttributeType: S
- AttributeName: notsend
AttributeType: N
KeySchema:
- AttributeName: email
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
GlobalSecondaryIndexes:
- IndexName: notsend-index
KeySchema:
- AttributeName: notsend
KeyType: HASH
Projection:
ProjectionType: ALL
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
Tags:
- Key: "username"
Value: "inamura"
Outputs:
DynamoDBArn:
Value: !GetAtt DynamoDB.Arn
Export:
Name: !Sub "cfn-dynamodb-${TableName}"
5.2.DynamoDBに値を登録
・DynamoDB
に値を登録するためにAWS CLI
を利用
5.2.1.jsonファイルを用意
{
"mailaddress": [
{
"PutRequest": {
"Item": {
"email": {"S":"XXXXXXXXXX@gmail.com"},
"username": {"S":"InamuraTeppei"},
"notsend": {"N":"0"},
"send": {"N":"1"}
}
}
}
]
}
5.2.2.AWS CLIを利用してデータをインポート
・下記コマンドをターミナルから入力してDynamoDB
のテーブルへ反映させる
aws dynamodb batch-write-item --request-items file://mailaddress.json
5.2.3.マネジメントコンソールから確認
・DynamoDB
> 左ペイン:テーブル の 項目を探索
> 確認したいテーブルを選択
6.Lambda(sendqueue)作成:DynamoDBに該当カラムを持つ場合 SQSを発行する構築
・後続手順でEventBridge
を構築した後にコメントアウトしているパーミッション(AWS::Lambda::Permission)
部分を修正する
・DynamoDB
のテーブルから notsend
が 0 のアイテムを取得
・取得したアイテムのsend
を 0 に更新
→ notsend
が 0 であれば、一度送っていてもSQSで後続のLambda(sendmail)へ値を渡し、後続Lambdaでsend
しているかどうか?をチェックする仕組み
・SQS
にメッセージとして登録
※ IAM部分のアカウトIDは XXXXXXXXXXXX
となっていますので、自身のアカウントIDを利用ください
AWSTemplateFormatVersion: '2010-09-09'
Description:
Lambda Create
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Lambda Configuration"
Parameters:
- FunctionName
- Description
- Handler
- MemorySize
- Runtime
- Timeout
- TagsName
# ------------------------------------------------------------#
# InputParameters
# ------------------------------------------------------------#
Parameters:
FunctionName:
Type: String
Default: "cfn-lmd-sendqueue-inamura"
Description:
Type: String
Default: "cfn-lmd--sendqueue-inamura"
Handler:
Type: String
Default: "index.lambda_handler"
MemorySize:
Type: String
Default: "128"
Runtime:
Type: String
Default: "python3.9"
Timeout:
Type: String
Default: "10"
TagsName:
Type: String
Default: "inamura"
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# Lambda
# ------------------------------------------------------------#
Lambda:
Type: 'AWS::Lambda::Function'
Properties:
Code:
ZipFile: |
import boto3
import urllib.parse
import json
from boto3.dynamodb.conditions import Key, Attr
import os
BUCKET = os.environ['S3']
TEMPLATE = os.environ['TEMPLATE']
def lambda_handler(event, context):
print('Loading function')
#DynamoDB boto3操作 Tableオブジェクト取得
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('mailaddress')
#SQS boto3操作 キュー取得
sqs = boto3.resource('sqs')
queue = sqs.get_queue_by_name(QueueName='cfn-sqs-inamura')
#環境変数からバケット名 オブジェクト名取得
bucket = BUCKET
template = TEMPLATE
#DynamoDB(table) から notsend 0 を絞り込んで取得
response = table.query(
IndexName='notsend-index',
KeyConditionExpression=Key('notsend').eq(0)
)
#絞り込んだテーブル情報 response['Item']から send 0 にプリペーアドクエリ更新
for item in response['Items']:
table.update_item(
Key={'email' : item['email']},
UpdateExpression="set send=:val",
ExpressionAttributeValues= {
':val' : 0
}
)
#SQSにメッセージとして登録
sqsresponse = queue.send_message(
MessageBody=item['email'],
MessageAttributes={
'username' : {
'DataType' : 'String',
'StringValue' : item['username']
},
'bucket' : {
'DataType' : 'String',
'StringValue' : bucket
},
'template' : {
'DataType' : 'String',
'StringValue' : template
}
}
)
#ログ出力
print(json.dumps(sqsresponse))
Description: !Ref Description
FunctionName: !Ref FunctionName
Handler: !Ref Handler
MemorySize: !Ref MemorySize
Runtime: !Ref Runtime
Timeout: !Ref Timeout
Role: !GetAtt LambdaRole.Arn
Environment:
Variables:
##削除する際は TriggerLambdaPermission をコメントアウトして Lambda を更新する
SNS: !ImportValue cfn-sns-topic-inamura-arn
S3: !ImportValue cfn-s3-BucketName
##ここまで
TEMPLATE: template-mail.txt
Tags:
- Key: "User"
Value: !Ref TagsName
DeadLetterConfig:
TargetArn: !ImportValue cfn-dlq-inamura-queuearn
LambdaRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${FunctionName}-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action: "sts:AssumeRole"
Principal:
Service: lambda.amazonaws.com
Policies:
- PolicyName: !Sub "${FunctionName}-policy"
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "logs:CreateLogStream"
- "logs:PutLogEvents"
- "logs:CreateLogGroup"
Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
- Effect: "Allow"
Action:
- "sqs:*"
Resource: "arn:aws:sqs:ap-northeast-1:XXXXXXXXXXXX:*"
- Effect: "Allow"
Action:
- "s3:*"
Resource: "arn:aws:s3:::*"
- Effect: "Allow"
Action:
- "dynamodb:*"
Resource: "arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:*"
# #削除する際は TriggerLambdaPermission をコメントアウトして Lambda を更新する
# TriggerLambdaPermission:
# Type: AWS::Lambda::Permission
# Properties:
# FunctionName: !Ref FunctionName
# Action: lambda:InvokeFunction
# Principal: events.amazonaws.com
# SourceArn: !ImportValue cfn-evb-checkdynamodb-inamura-arn
# #ここまで
# ------------------------------------------------------------#
# Output Parameters
#------------------------------------------------------------#
Outputs:
LambdaArn:
Value: !GetAtt Lambda.Arn
Export:
Name: !Sub "${FunctionName}-arn"
LambdaName:
Value: !Ref FunctionName
Export:
Name: !Sub "${FunctionName}-name"
7.EventBridge作成:CronでLambda(sendqueue)とトリガーを構築
7.1.CFnでEventBridge構築
AWSTemplateFormatVersion: "2010-09-09"
Description:
EventBridge gets s3 events and sends them to lambda
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Eventbridge Configuration"
Parameters:
- RuleName
- EventBusName
- State
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
EventBusName:
Type: String
Default: "default"
RuleName:
Type: String
Default: "cfn-evb-checkdynamodb-inamura"
State:
Type: String
Default: "ENABLED"
# ------------------------------------------------------------#
# EventBridge
# ------------------------------------------------------------#
Resources:
EventsRuleCron:
Type: AWS::Events::Rule
Properties:
Description: "Check DynamoDB and send to Lambda"
EventBusName: !Ref EventBusName
Name: !Ref RuleName
State: !Ref State
ScheduleExpression: cron(0/10 * * * ? *)
Targets:
- Arn: !ImportValue cfn-lmd-sendqueue-inamura-arn
Id: cfn-lmd-inamura
# ------------------------------------------------------------#
# Output Parameters
#------------------------------------------------------------#
Outputs:
EventBridgeArn:
Value: !GetAtt EventsRuleCron.Arn
Export:
Name: !Sub "${RuleName}-arn"
7.2.手順6.で構築したLambdaのコメントアウト部分を修正し更新する
【修正箇所のみ抜粋】
・!ImportValue
でEventBridge
が作成されていないと構築できなかった
TriggerLambdaPermission:
Type: AWS::Lambda::Permission
Properties:
FunctionName: !Ref FunctionName
Action: lambda:InvokeFunction
Principal: events.amazonaws.com
SourceArn: !ImportValue cfn-evb-checkdynamodb-inamura-arn
挙動の確認
前提条件:EventBridgeが10分ごとにLambdaをキックするので、10/20・・・分に起動する
①メールが届いたか確認する
②LambdaのCloudWatchLogsの出力のされ方
【sendqueue
のCloudWatchLogs】
・EventBridge
でCron
されるたびにLambda
が実行している
【sendmail
のCloudWatchLogs】
・DynamoDB
のカラムnotsend
が 1 のため Queue が発行されず実行されない
【届いていない場合①】Lambda(sendqueue)のCloudWatchLogsを確認する
・前半の処理部分(EventBridge、DynamoDB、SQS系があやしい)のエラーの場合
【届いていない場合②】Lambda(sendmail)のCloudWatchLogsを確認する
・後半の処理部分(SQS、DynamoDB、SNS系があやしい)のエラーの場合
削除順番
基本的には構築した順番の逆ですが、!ImportValue
をしているので削除順がややこしくなっている部分があります。
1.Lambda(sendqueue)
のEnvironment
部分及び、TriggerLambdaPermission
部分をコメントアウトして更新をする(!ImportValue
で引用している部分)
2.DynamoDB
を削除
3.EventBridge
を削除
4.Lambda(sendqueue)
を削除
5.Lambda(sendmail)
を削除
6.SQS
を削除
7.S3
のバケットを空にし、S3
を削除
8.SNS
を削除
さいごに
盛りだくさんの内容になりましたが、個人的にはCFnでDynamoDBを利用するという目的は果たせたかと思います。ただし、まだまだ使えるのかと問われると基本となるクエリなどの本質的な理解が出来ていないとLambdaを書きながら痛感しました。
次回はAPIGateway経由で、こちらで利用したDynamoDB
に名前やアドレスを CLIからではなくて、実際のフロント画面から送ったりして挙動を確認したいと思います。
参考文献
AWS Lambda実践ガイド 第2版 (impress top gear) 著:大澤文孝