takafumi blog

日々の勉強メモ

aws sam (Serverless Application Model)に入門する

Infrastructure as Code入門としてaws samでLambdaを作るところからはじめてみる

aws-cliaws-samはinstall済み

sample templateから基本的なアプリケーションをビルト

仕組み的には以下のような順序で作成される

  1. ローカルでsamコマンドでアプリケーションを作成
  2. ローカルからsam deployでcloudformationを呼び出しアプリケーションをデプロイする
  3. S3へテンプレートが保存される
  4. API GatewayとLambdaが作成される

f:id:takafumi-s:20210808235600p:plain

aws samのアプリケーションを作成

$ sam init

# まずはawsのtemplateを選択して使う
# template一覧は以下
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1


# パッケージはシンプルに
# lambda用のファイルはzipで固め
# cloudformationでS3にアップロードされる
#
# 2のイメージはECR周りの知識が必要なのでそのうち試す
What package type would you like to use?
        1 - Zip (artifact is a zip uploaded to S3)
        2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 1

# go1.xで作っていく
Which runtime would you like to use?
        1 - nodejs14.x
        2 - python3.8
        3 - ruby2.7
        4 - go1.x
        5 - java11
        6 - dotnetcore3.1
        7 - nodejs12.x
        8 - nodejs10.x
        9 - python3.7
        10 - python3.6
        11 - python2.7
        12 - ruby2.5
        13 - java8.al2
        14 - java8
        15 - dotnetcore2.1
Runtime: 4

# cloudformation, API Gatewayの名前
# S3, Lambdaのprefixとして使われる
Project name [sam-app]:

Cloning from https://github.com/aws/aws-sam-cli-app-templates

# まずは単独のLambdaで作るので1を選択
AWS quick start application templates:
        1 - Hello World Example
        2 - Step Functions Sample App (Stock Trader)
Template selection: 1

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: go1.x
    Dependency Manager: mod
    Application Template: hello-world
    Output Directory: .

    Next steps can be found in the README file at ./sam-app/README.md

この段階でgolangのLambdaに適した構成が作成される
template.yamlはcloudformationと共通フォーマット
将来的にaws samの範囲より拡張された場合はcloudformationで使う事もできる

$ tree sam-app
sam-app
├── Makefile
├── README.md
├── hello-world
│   ├── go.mod
│   ├── go.sum
│   ├── main.go
│   └── main_test.go
└── template.yaml

1 directory, 7 files

main.goは以下のようにLambdaでGetリクエストを受ける基本的な構成になっている

package main

import (
        "errors"
        "fmt"
        "io/ioutil"
        "net/http"

        "github.com/aws/aws-lambda-go/events"
        "github.com/aws/aws-lambda-go/lambda"
)

var (
        // DefaultHTTPGetAddress Default Address
        DefaultHTTPGetAddress = "https://checkip.amazonaws.com"

        // ErrNoIP No IP found in response
        ErrNoIP = errors.New("No IP in HTTP response")

        // ErrNon200Response non 200 status code in response
        ErrNon200Response = errors.New("Non 200 Response found")
)

func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
        resp, err := http.Get(DefaultHTTPGetAddress)
        if err != nil {
                return events.APIGatewayProxyResponse{}, err
        }

        if resp.StatusCode != 200 {
                return events.APIGatewayProxyResponse{}, ErrNon200Response
        }

        ip, err := ioutil.ReadAll(resp.Body)
        if err != nil {
                return events.APIGatewayProxyResponse{}, err
        }

        if len(ip) == 0 {
                return events.APIGatewayProxyResponse{}, ErrNoIP
        }

        return events.APIGatewayProxyResponse{
                Body:       fmt.Sprintf("Hello, %v", string(ip)),
                StatusCode: 200,
        }, nil
}

func main() {
        lambda.Start(handler)
}

アプリケーションをbuild

$ sam build
Building codeuri: ./sam-app/hello-world runtime: go1.x metadata: {} functions: ['HelloWorldFunction']
Running GoModulesBuilder:Build

Build Succeeded

Built Artifacts  : .aws-sam/build
Built Template   : .aws-sam/build/template.yaml

Commands you can use next
=========================
[*] Invoke Function: sam local invoke
[*] Deploy: sam deploy --guided

ローカルでアプリケーションを実行

sam local start-apiと実行する事で、ローカルでsamでbuildしたAPIを実行できる

$ 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
2021-08-08 23:37:49  * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)

この状態でリクエストを投げると、dockerイメージが作成&実行され、レスポンスを返す

$ curl http://127.0.0.1:3000/hello
Hello, 11.111.111.111

sam local start-apiのログ

Invoking hello-world (go1.x)
Image was not found.
Building image......................................................................................................
Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-go1.x:rapid-1.27.2.

Mounting ./sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container
START RequestId: fa806430-6835-4b88-acd6-4e1b857bcd4a Version: $LATEST
END RequestId: fa806430-6835-4b88-acd6-4e1b857bcd4a
REPORT RequestId: fa806430-6835-4b88-acd6-4e1b857bcd4a  Init Duration: 0.07 ms  Duration: 1010.38 ms    Billed Duration: 1100 ms        Memory Size: 128 MB     Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2021-08-08 23:43:07 127.0.0.1 - - [08/Aug/2021 23:43:07] "GET /hello HTTP/1.1" 200 -
$ docker ps
CONTAINER ID   IMAGE                                                   COMMAND                  CREATED         STATUS        PORTS                      NAMES
fa8dda6a0f15   amazon/aws-sam-cli-emulation-image-go1.x:rapid-1.27.2   "/var/rapid/aws-lamb…"   2 seconds ago   Up 1 second   127.0.0.1:6436->8080/tcp   vigorous_allen

アプリケーションをawsへデプロイする

--guided をつけると会話形式で設定できる

$ sam deploy --guided

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Not found

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app]:
        AWS Region [ap-northeast-1]:
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]:
        #SAM needs permission to be able to create roles to connect to the resources in your template
        Allow SAM CLI IAM role creation [Y/n]:
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]:
        SAM configuration file [samconfig.toml]:
        SAM configuration environment [default]:

        Looking for resources needed for deployment: Not found.
        Creating the required resources...
        Successfully created!

                Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xarl3ki5fc62
                A different default S3 bucket can be set in samconfig.toml

        Saved arguments to config file
        Running 'sam deploy' for future deployments will use the parameters saved above.
        The above parameters can be changed by modifying samconfig.toml
        Learn more about samconfig.toml syntax at
        https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html

Uploading to sam-app/7ad10cf1c8bd04b9d2c1ad18dd4297c0  4328737 / 4328737  (100.00%)

        Deploying with following values
        ===============================
        Stack name                   : sam-app
        Region                       : ap-northeast-1
        Confirm changeset            : False
        Deployment s3 bucket         : aws-sam-cli-managed-default-samclisourcebucket-xarl3ki5fc62
        Capabilities                 : ["CAPABILITY_IAM"]
        Parameter overrides          : {}
        Signing Profiles             : {}

Initiating deployment
=====================
Uploading to sam-app/17fb0b7caff4b6a85cdca466c28c1236.template  1154 / 1154  (100.00%)

Waiting for changeset to be created..

CloudFormation stack changeset
----------------------------------------------------------------------------------------------------
Operation    LogicalResourceId                           ResourceType                   Replacement
----------------------------------------------------------------------------------------------------
+ Add        HelloWorldFunctionCatchAllPermissionProd    AWS::Lambda::Permission        N/A
+ Add        HelloWorldFunctionRole                      AWS::IAM::Role                 N/A
+ Add        HelloWorldFunction                          AWS::Lambda::Function          N/A
+ Add        ServerlessRestApiDeployment47fc2d5f9d       AWS::ApiGateway::Deployment    N/A
+ Add        ServerlessRestApiProdStage                  AWS::ApiGateway::Stage         N/A
+ Add        ServerlessRestApi                           AWS::ApiGateway::RestApi       N/A
----------------------------------------------------------------------------------------------------

Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:111111111111:changeSet/samcli-deploy1628426562/db1f0927-131d-4bf1-9b12-aacf949eacda


2021-08-08 21:42:54 - Waiting for stack create/update to complete

CloudFormation events from changeset
------------------------------------------------------------------------------------------------------------------------------
ResourceStatus         ResourceType                   LogicalResourceId                           ResourceStatusReason
------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS     AWS::IAM::Role                 HelloWorldFunctionRole                      -
CREATE_IN_PROGRESS     AWS::IAM::Role                 HelloWorldFunctionRole                      Resource creation Initiated
CREATE_COMPLETE        AWS::IAM::Role                 HelloWorldFunctionRole                      -
CREATE_IN_PROGRESS     AWS::Lambda::Function          HelloWorldFunction                          -
CREATE_IN_PROGRESS     AWS::Lambda::Function          HelloWorldFunction                          Resource creation Initiated
CREATE_COMPLETE        AWS::Lambda::Function          HelloWorldFunction                          -
CREATE_IN_PROGRESS     AWS::ApiGateway::RestApi       ServerlessRestApi                           -
CREATE_IN_PROGRESS     AWS::ApiGateway::RestApi       ServerlessRestApi                           Resource creation Initiated
CREATE_COMPLETE        AWS::ApiGateway::RestApi       ServerlessRestApi                           -
CREATE_IN_PROGRESS     AWS::Lambda::Permission        HelloWorldFunctionCatchAllPermissionProd    -
CREATE_IN_PROGRESS     AWS::Lambda::Permission        HelloWorldFunctionCatchAllPermissionProd    Resource creation Initiated
CREATE_IN_PROGRESS     AWS::ApiGateway::Deployment    ServerlessRestApiDeployment47fc2d5f9d       -
CREATE_COMPLETE        AWS::ApiGateway::Deployment    ServerlessRestApiDeployment47fc2d5f9d       -
CREATE_IN_PROGRESS     AWS::ApiGateway::Deployment    ServerlessRestApiDeployment47fc2d5f9d       Resource creation Initiated
CREATE_IN_PROGRESS     AWS::ApiGateway::Stage         ServerlessRestApiProdStage                  -
CREATE_IN_PROGRESS     AWS::ApiGateway::Stage         ServerlessRestApiProdStage                  Resource creation Initiated
CREATE_COMPLETE        AWS::ApiGateway::Stage         ServerlessRestApiProdStage                  -
CREATE_COMPLETE        AWS::Lambda::Permission        HelloWorldFunctionCatchAllPermissionProd    -
CREATE_COMPLETE        AWS::CloudFormation::Stack     sam-app                                     -
------------------------------------------------------------------------------------------------------------------------------

CloudFormation outputs from deployed stack
-----------------------------------------------------------------------------------------------------------
Outputs
-----------------------------------------------------------------------------------------------------------
Key            HelloWorldFunctionIamRole
Description    Implicit IAM Role created for Hello World function
Value          arn:aws:iam::111111111111:role/sam-app-HelloWorldFunctionRole-MGSTGE9WCIMR

Key            HelloWorldAPI
Description    API Gateway endpoint URL for Prod environment for First Function
Value          https://aaaaaaaaaa.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/

Key            HelloWorldFunction
Description    First Lambda Function ARN
Value          arn:aws:lambda:ap-northeast-1:111111111111:function:sam-app-HelloWorldFunction-pMOSVaxRjbuN
-----------------------------------------------------------------------------------------------------------

Successfully created/updated stack - sam-app in ap-northeast-1

これにより API Gateway経由でLambdaを呼び出せるようところまで作成される

デプロイ結果の確認

OutputsにあるHelloWorldAPIへアクセスしてみると、レスポンスが返ってくる

$ curl - 'https://aaaaaaaaaa.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/'
HTTP/2 200
content-type: application/json
content-length: 22
date: Sun, 08 Aug 2021 13:41:16 GMT

Hello, 11.111.111.111

参考

docs.aws.amazon.com

docs.aws.amazon.com