はじめに
簡単なサーバーレス環境の構築をCloudFormationを使って構築してみました。
背景として、よくある構成だと思うので、プロジェクトなどでちょっとした検証をするときに参考になるかと思い整理しました。
構成
テンプレート
template.yaml
AWSTemplateFormatVersion: 2010-09-09
Parameters:
BucketName:
Type: String
PutLambdaImageUri:
Type: String
DeleteLambdaImageUri:
Type: String
Resources:
# ====================
# S3 Buckets
# ====================
Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref BucketName
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: True
BlockPublicPolicy: True
IgnorePublicAcls: True
RestrictPublicBuckets: True
# ====================
# Step Functions
# ====================
StateMachine:
Type: AWS::StepFunctions::StateMachine
Properties:
DefinitionString: !Sub
- |-
{
"Comment": "Put and Delete S3 Object",
"StartAt": "Put",
"States": {
"Put": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"Payload.$": "$",
"FunctionName": "${PutLambdaArn}"
},
"Next": "Wait",
"OutputPath": "$.Payload"
},
"Wait": {
"Type": "Wait",
"Seconds": 60,
"Next": "Delete"
},
"Delete": {
"Type": "Task",
"Resource": "arn:aws:states:::lambda:invoke",
"Parameters": {
"Payload.$": "$",
"FunctionName": "${DeleteLambdaArn}"
},
"End": true
}
}
}
- PutLambdaArn: !GetAtt PutLambda.Arn
DeleteLambdaArn: !GetAtt DeleteLambda.Arn
RoleArn: !GetAtt StateMachineRole.Arn
# ====================
# Lambda Functions
# ====================
PutLambda:
Type: AWS::Lambda::Function
Properties:
Role: !GetAtt LambdaRole.Arn
PackageType: Image
Code:
ImageUri: !Ref PutLambdaImageUri
Environment:
Variables:
BUCKET_NAME: !Ref Bucket
DeleteLambda:
Type: AWS::Lambda::Function
Properties:
Role: !GetAtt LambdaRole.Arn
PackageType: Image
Code:
ImageUri: !Ref DeleteLambdaImageUri
Environment:
Variables:
BUCKET_NAME: !Ref Bucket
# ====================
# EventBridge Rules
# ====================
StateMachineEventsRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: rate(5 minutes)
State: ENABLED
Targets:
- Arn: !GetAtt StateMachine.Arn
Id: !GetAtt StateMachine.Name
RoleArn: !GetAtt EventsRuleRole.Arn
# ====================
# Roles
# ====================
LambdaRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
- arn:aws:iam::aws:policy/AmazonS3FullAccess
StateMachineRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- !Sub states.${AWS::Region}.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: LambdaExecutionPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- lambda:InvokeFunction
Resource: "*"
EventsRuleRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- events.amazonaws.com
Action:
- sts:AssumeRole
Path: /
Policies:
- PolicyName: StateMachineExecutionPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- states:StartExecution
Resource: "*"
Lambda
更新Lambda
update.py
import json
import os
from datetime import datetime
import boto3
def handler(_event, _context):
client = boto3.client("s3")
key = f"sample-{datetime.timestamp(datetime.now())}.json"
client.put_object(
Body=json.dumps({"message": "sample"}).encode("utf-8"),
Bucket=os.getenv("BUCKET_NAME"),
Key=key,
)
return {
"statusCode": 200,
"body": json.dumps("Put S3 Object"),
"key": key,
}
削除Lambda
delete.py
import json
import os
import boto3
def handler(event, _context):
key = event["key"]
client = boto3.client("s3")
client.delete_object(
Bucket=os.getenv("BUCKET_NAME"),
Key=key,
)
return {
"statusCode": 200,
"body": json.dumps("Delete S3 Object"),
}
まとめ
今回であれば、結果だけ見ると何もしていないように見えますが、簡単なサーバーレスの構成を検討構築してみました。
あまり難しいことはやっていないので、AWS環境がある方はぜひ試してみてください。