AWS SAMとGo言語で体感するサーバーレス開発
今回はAWS SAMを使用してサーバーレスアプリケーションを構築していきます。
API GatewayをトリガーとしてLambda関数が発火するという非常にシンプルな内容です。そのためサーバーレス開発のイメージを掴みやすいのではないかと思います。
AWS SAMとは
AWS SAM(Serverless Application Model)とは、AWS上にサーバーレスアプリケーションを構築することができるフレームワークです。YAMLまたはJSON形式で構成を記述することができます。
コマンドラインツールとしてAWS SAM CLIも提供されており、ローカル環境でもLambda関数を実行することができます。
準備
AWS CLIとAWS SAM CLIを導入します。pipやbrewといった、お好きなパッケージ管理ツールでインストールしてください。
$ pip install awscli
$ pip install aws-sam-cli
$ brew install awscli
$ brew install aws-sam-cli
AWS CLIで利用するプロファイルも設定しておきましょう。すでに設定済みの場合は不要です。
$ aws configure --profile iamSAM
AWS Access Key ID [None]: ******************
AWS Secret Access Key ID [None]: ******************
Default region name [None]: ap-northeast-1
Default output format [None]: json
サーバーレスアプリケーションのベースを作成
sam init
コマンドでサーバーレスアプリケーションの雛形を作成します。
今回はGoで関数を作成していきます。
$ sam init --runtime go1.x --name aws-sam-golang
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 1
Cloning app templates from https://github.com/awslabs/aws-sam-cli-app-templates.git
-----------------------
Generating application:
-----------------------
Name: aws-sam-golang
Runtime: go1.x
Dependency Manager: mod
Application Template: hello-world
Output Directory: .
Next steps can be found in the README file at ./aws-sam-golang/README.md
$ cd aws-sam-golang
$ tree
.
├── Makefile
├── README.md
├── hello-world
│ ├── main.go
│ └── main_test.go
└── template.yaml
1 directory, 5 files
hello-world/main.go
が、今回のLambda関数の実装を行うファイルです。 template.yaml
にはサーバーレスアプリケーションの関数定義が記述されています。
また、今回はGoのライブラリバージョン管理にModules
を使います。
Modules
についてはこちらの記事を御覧ください。
$ go mod init
go: creating new go.mod: module hoge/fuga/aws-sam-golang
雛形の実行テスト
sam local start-api
コマンドで、ローカルでもLambda関数を実行することができます(Docker上で動作します)。
Lambda関数の実行にはバイナリが必要ですので、make
コマンドでビルドしましょう。
$ make build
GOOS=linux GOARCH=amd64 go build -o hello-world/hello-world ./hello-world
$ sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-01-19 20:38:36 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
Invoking hello-world (go1.x)
この状態で、curl
コマンドでAPIを叩いてみましょう。
$ curl http://localhost:3000/hello
Hello, 118.***.***.**
雛形のhello-world/main.go
に従い、自分のグローバルIPアドレスが返ってきました。
SAM Local側では次のようなログが確認できます。
Fetching lambci/lambda:go1.x Docker container image......
Mounting /Users/daisakuhazui/develop/aws-sam-golang/hello-world as /var/task:ro,delegated inside runtime container
START RequestId: c0308535-1ed4-15d2-a58d-ff1ac09907ad Version: $LATEST
END RequestId: c0308535-1ed4-15d2-a58d-ff1ac09907ad
REPORT RequestId: c0308535-1ed4-15d2-a58d-ff1ac09907ad Init Duration: 169.68 ms Duration: 891.58 ms Billed Duration: 900 ms Memory Size: 128 MB Max Memory Used: 27 MB
No Content-Type given. Defaulting to 'application/json'.
2020-01-19 20:38:58 127.0.0.1 - - [19/Jan/2020 20:38:58] "GET /hello HTTP/1.1" 200 -
Lambda関数の修正
雛形の動作確認が取れたので、次はLambda関数に手を加えましょう。
先ほど確認した通り、現状のコードはhttp://localhost:3000/hello
へのリクエストに対しIPアドレスを返す実装になっています。
この実装をhttp://localhost:3000/hello/{user}
に対してHello, {user}
と返すよう、これから修正していきます。
`main.go`
package main
(中略)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
user, _ := request.PathParameters["user"]
return events.APIGatewayProxyResponse{
Body: fmt.Sprintf("Hello, %s", user),
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
関数を修正したらtemplate.yaml
にも修正が必要です。
`template.yaml`
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-sam-golang
Sample SAM Template for aws-sam-golang
Globals:
Function:
Timeout: 5
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: hello-world
Runtime: go1.x
Tracing: Active
Events:
CatchAll:
Type: Api
Properties:
Path: /hello/{user} # パスパラメータをセット
Method: GET
Environment:
Variables:
PARAM1: VALUE
・
・
・
Type: AWS::Serverless::Function
でLambda関数であることを表し、Events
配下のCatchAll
でAPIの定義を行っています。
今回はパスパラメータを受け取れるようにPath
の値を修正しました。
動作確認
関数とテンプレートの修正が終わったのでローカルで動作確認していきます。
$ make build
GOOS=linux GOARCH=amd64 go build -o hello-world/hello-world ./hello-world
$ sam local start-api
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello/{user} [GET]
You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template
2020-01-19 20:47:07 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
Invoking hello-world (go1.x)
今度はパスパラメータを与えてcurl
コマンドを叩いてみましょう。
$ curl http://localhost:3000/hello/Daisaku
Hello, Daisaku
OKです。想定通りの動きになっています。
AWS上にデプロイ
ローカルで動作確認を終えたので、実際にAWS上にデプロイしてみましょう。
$ sam validate --profile iamSAM
/Users/daisakuhazui/develop/aws-sam-golang/template.yaml is a valid SAM Template
$ sam package
--template-file template.yaml
--s3-bucket <YOUR BUCKET NAME>
--output-template-file packaged.yaml
--profile iamSAM
Uploading to a1342a2f62dce02aba5dfa11e11a6d1d 5023955 / 5023955.0 (100.00%)
Successfully packaged artifacts and wrote output template to file packaged.yaml.
Execute the following command to deploy the packaged template
sam deploy --template-file /Users/daisakuhazui/develop/aws-sam-golang/packaged.yaml --stack-name <YOUR STACK NAME>
$ sam deploy
--profile iamSAM
--region ap-northeast-1
--template-file /Users/daisakuhazui/develop/aws-sam-golang/packaged.yaml
--stack-name aws-sam-golang
--capabilities CAPABILITY_IAM
Deploying with following values
===============================
Stack name : aws-sam-golang
Region : ap-northeast-1
Confirm changeset : False
Deployment s3 bucket : None
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Initiating deployment
=====================
Waiting for changeset to be created..
(中略)
Stack aws-sam-golang outputs:
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
OutputKey-Description OutputValue
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
HelloWorldFunctionIamRole - Implicit IAM Role created for Hello World function arn:aws:iam::************:role/aws-sam-golang-HelloWorldFunctionRole-*************
HelloWorldAPI - API Gateway endpoint URL for Prod environment for First Function https://**********.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
HelloWorldFunction - First Lambda Function ARN arn:aws:lambda:ap-northeast-1:************:function:aws-sam-golang-
HelloWorldFunction-*************
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - aws-sam-golang in ap-northeast-1
これでAWS上へのデプロイが完了しました。
最後にAPI Gatewayのエンドポイントにアクセスしてみましょう。(API Gateway endpoint URL for Prod environment for First Function
の右にあるURL)
$ curl https://**********.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/Daisaku
Hello, Daisaku
API Gateway経由でも期待通りのレスポンスが返ってきました。
まとめ
AWS SAMとGo言語を使って非常にシンプルなサーバーレス構成を構築しました。
昨年のアップデートでAWS SAMのデプロイ方法が非常に簡単になり、とても使いやすくなったんじゃないかなと思います。(sam package
とsam deploy
のパラメータは複雑ですが...)
参考になれば幸いです。
近年、MMMはAWS Lambdaに力を入れています。ぜひ以下のページもご覧ください。