はじめに
今回は AWS Serverless Application Model (AWS SAM)を試します。
アクセスすると自己削除するWebページを作成します。
[Lambda関数・SAMテンプレート]
(https://github.com/tanaka-takurou/serverless-application-ephemerality-page-go/tree/minimum)
準備
AWS SAM CLI をインストールします
S3の準備をします
[AWS SAMの資料]
AWS サーバーレスアプリケーションモデル
AWS Serverless Application Model
AWS SAM テンプレート作成
AWS SAM テンプレートで API-Gateway , Lambdaの設定をします。
[参考資料]
AWS SAM テンプレートを作成する
template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Serverless Application Ephemerality
Parameters:
ApplicationName:
Type: String
Default: 'ServerlessApplicationEphemeralityMinimum'
EphemeralityFunctionName:
Type: String
Default: 'EphemeralityFunctionMinimum'
Metadata:
AWS::ServerlessRepo::Application:
Name: Serverless-Application-Minimum
Description: 'This application is deleted when accessed.'
Author: tanaka-takurou
SpdxLicenseId: MIT
LicenseUrl: LICENSE.txt
ReadmeUrl: README.md
Labels: ['ServerlessRepo']
HomePageUrl: https://github.com/tanaka-takurou/serverless-application-ephemerality-page-go/tree/minimum
SemanticVersion: 0.0.2
SourceCodeUrl: https://github.com/tanaka-takurou/serverless-application-ephemerality-page-go/tree/minimum
Resources:
EphemeralityApi:
Type: AWS::Serverless::HttpApi
EphemeralityFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Ref EphemeralityFunctionName
CodeUri: bin/
Handler: main
MemorySize: 256
Runtime: go1.x
Description: 'Front Function'
Role: !GetAtt EphemeralityFunctionRole.Arn
Events:
EphemeralityApi:
Type: HttpApi
Properties:
Path: '/'
Method: get
ApiId: !Ref EphemeralityApi
Environment:
Variables:
COUNT: "0"
LIMIT: "0"
REGION: !Ref AWS::Region
STACK_NAME: !Ref AWS::StackName
FUNCTION_NAME: !Ref EphemeralityFunctionName
EphemeralityApiPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunction
FunctionName: !Ref EphemeralityFunction
Principal: apigateway.amazonaws.com
EphemeralityFunctionRole:
Type: AWS::IAM::Role
Properties:
MaxSessionDuration: 3600
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'lambda.amazonaws.com'
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: KillFunctionPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
- Effect: 'Allow'
Action:
- 'cloudformation:DescribeStackResources'
- 'cloudformation:DeleteStack'
Resource: '*'
- Effect: 'Allow'
Action:
- 'lambda:*'
- 'events:RemoveTargets'
- 'events:DeleteRule'
- 'iam:DeleteRolePolicy'
- 'iam:DeleteRole'
Resource: '*'
- Effect: 'Allow'
Action:
- 'apigateway:*'
Resource: '*'
Outputs:
APIURI:
Value: !Join [ '', [ 'https://', !Ref EphemeralityApi, '.execute-api.',!Ref 'AWS::Region','.amazonaws.com/'] ]
API-Gatewayの設定は以下の部分
EphemeralityApi:
Type: AWS::Serverless::HttpApi
Lambdaの設定は以下の部分
EphemeralityFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Ref EphemeralityFunctionName
CodeUri: bin/
Handler: main
MemorySize: 256
Runtime: go1.x
Description: 'Front Function'
Role: !GetAtt EphemeralityFunctionRole.Arn
Events:
EphemeralityApi:
Type: HttpApi
Properties:
Path: '/'
Method: get
ApiId: !Ref EphemeralityApi
Environment:
Variables:
COUNT: "0"
LIMIT: "0"
REGION: !Ref AWS::Region
STACK_NAME: !Ref AWS::StackName
FUNCTION_NAME: !Ref EphemeralityFunctionName
Lambda関数作成
※ Lambda関数は aws-lambda-go を利用し、cloudformationの周りの処理は aws-sdk-go-v2 を利用しました。
main.go
package main
import (
"os"
"log"
"context"
"strconv"
"net/http"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/external"
slambda "github.com/aws/aws-sdk-go-v2/service/lambda"
"github.com/aws/aws-sdk-go-v2/service/cloudformation"
)
var cfg aws.Config
func HandleRequest(ctx context.Context, request events.APIGatewayV2HTTPRequest) (events.APIGatewayProxyResponse, error) {
count, _ := strconv.Atoi(os.Getenv("COUNT"))
limit, _ := strconv.Atoi(os.Getenv("LIMIT"))
if count < limit {
client := slambda.New(cfg)
req := client.GetFunctionConfigurationRequest(&slambda.GetFunctionConfigurationInput{
FunctionName: aws.String(os.Getenv("FUNCTION_NAME")),
})
res, err := req.Send(ctx)
if err != nil {
log.Println(err)
} else {
env := res.GetFunctionConfigurationOutput.Environment.Variables
env["COUNT"] = strconv.Itoa(count + 1)
req_ := client.UpdateFunctionConfigurationRequest(&slambda.UpdateFunctionConfigurationInput{
FunctionName: aws.String(os.Getenv("FUNCTION_NAME")),
Environment: &slambda.Environment{
Variables: env,
},
})
_, err := req_.Send(ctx)
if err != nil {
log.Println(err)
}
}
} else {
client := cloudformation.New(cfg)
req := client.DeleteStackRequest(&cloudformation.DeleteStackInput{
StackName: aws.String(os.Getenv("STACK_NAME")),
})
_, err := req.Send(ctx)
if err != nil {
log.Println(err)
}
}
return events.APIGatewayProxyResponse{
StatusCode: http.StatusOK,
IsBase64Encoded: false,
Body: "<html><head><title>Serverless Application Ephemerality</title></head><body><span>Serverless Application Ephemerality</span></body></html>",
Headers: map[string]string{
"Content-Type": "text/html",
},
}, nil
}
func init() {
var err error
cfg, err = external.LoadDefaultAWSConfig()
cfg.Region = os.Getenv("REGION")
if err != nil {
log.Print(err)
}
}
func main() {
lambda.Start(HandleRequest)
}
スタックを削除するには DeleteStackRequest を使う
client := cloudformation.New(cfg)
req := client.DeleteStackRequest(&cloudformation.DeleteStackInput{
StackName: aws.String(os.Getenv("STACK_NAME")),
})
_, err := req.Send(ctx)
※ この処理により 作成したWebページが削除されます。
デプロイ
sam package --output-template-file packaged.yml --s3-bucket "${bucket}"
sam deploy --stack-name "${stack}" --capabilities CAPABILITY_IAM --template-file packaged.yml
※ ${bucket} には 「準備」 で作成した S3バケット名を入力
※ ${stack} には スタック名を入力 (既にあるスタックを指定すると、スタックを更新します)
・デプロイが完了すると、作成したWebページにアクセスできるようになります。
・デプロイ完了後 CloudFormationのスタック一覧 に表示されます。
パブリッシュ
sam package --output-template-file packaged.yml --s3-bucket "${bucket}"
sam publish --template packaged.yml" --region "${AWS_DEFAULT_REGION}"
※ ${bucket} には 「準備」 で作成した S3バケット名を入力
※ ${AWS_DEFAULT_REGION} には リージョン (ap-northeast-1 など) を入力
・パブリッシュ完了後 Serverless Application Repositoryのマイアプリケーション一覧 に表示されます。
削除
aws cloudformation delete-stack --stack-name "${stack}"
※ ${stack} には スタック名を入力
終わりに
Policy周りが原因でデプロイする際にエラーが発生することが多くありました。
使い慣れることで、AWS管理画面よりも簡単に、サーバレスアプリケーションの作成・削除・複製できそうです。