AWS SAMでアプリケーションをローカルテスト&デプロイを試してみた

AWS SAMのローカルテストとデプロイをデモンストレーションしてみました

AWS SAMでアプリケーションをローカルテスト&デプロイを試してみた
目次

TL;DR


☆ SAMの基本的な使い方
☆ ローカルデプロイの方法
☆ Cfnとの比較

 

はじめに


こちらの記事 で作成した環境をテンプレート化したい!と思ったので、 AWS SAMを使ってみました。 SAMはリソースをプロビジョニングできるだけでなく、ローカルでLambda、API Gatewayをテストできる便利ツールだったのでその使い方も紹介します。 途中、cloudformationコマンドとの比較もしていますのでご参考までに。

 

環境


  • mac OS:Monterey 12.0.1
  • AWS CLI:2.2.33
  • SAM CLI:1.35.0

 

1. SAMとは


  • AWS Serverless Application Modelの略
  • サーバーレスアプリケーション構築用のオープンソースフレームワーク
  • YAML,JSON形式でテンプレート記述
  • CloudFormationの拡張機能で、簡単にテンプレートを記述することが可能
  • SAM CLIあり

 

2. SAM CLIのインストール


こちらからどうぞ

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html

 

3. SAM利用の流れ


1. SAMテンプレートの記述
1. パッケージング
1. デプロイ

 

3-1. SAMテンプレートの記述


テンプレート構造

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/sam-specification-template-anatomy.html

実際のコード

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM Serverless demo
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translation-function
      CodeUri: translation-function/
      Handler: translation-function.lambda_handler
      Runtime: python3.8
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId:
              Ref: TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api
      StageName: dev
      EndpointConfiguration: REGIONAL
  TranslateDynamoDbTbl:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: tranlate-history
      PrimaryKey:
        Name: timestamp
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

1. リソースタイプの選択

AWS::Serverless::Function AWS::Serverless::Api AWS::Serverless::SimpleTable など

2. リソースタイプごとに必要なプロパティを記述

AWS::Serverless::Functionであれば、 Handler,Runtimeが必須 CodeUri,InlineCodeのいずれか必須 など

 

3-2. パッケージング 


デプロイするためにzip化し、S3にアップロードする

  • s3パスをSAMテンプレートのCodeUriに記載する必要がある
  • パッケージングコマンドで、アプリケーションをzip化し、CodeUriを書き換えている

 

パッケージングには2つの方法がある

  • cloudformationコマンド
  • SAM CLI

 

cloudformationコマンド実行

※AWS CLIインストールかつログイン済みであることが前提

aws cloudformation package \
--template-file template.yaml \
--s3-bucket serverless-sam-demo \
--output-template-file packaged-template.yaml

コマンド実行後、下記ファイルが出力される

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM Serverless demo
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translation-function
      CodeUri: s3://serverless-sam-demo/*************
      Handler: translation-function.lambda_handler
      Runtime: python3.8
      Timeout: 5
      MemorySize: 256
      Policies:
      - TranslateFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId:
              Ref: TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api
      StageName: dev
      EndpointConfiguration: REGIONAL
  TranslateDynamoDbTbl:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: translate-history
      PrimaryKey:
        Name: timestamp
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

パッケージ前

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM Serverless demo
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translation-function
      CodeUri: translation-function/
      Handler: translation-function.lambda_handler

パッケージ後

Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translation-function
      CodeUri: s3://serverless-sam-demo/*************
      Handler: translation-function.lambda_handler

先ほどのyamlファイルのcodeuriの表記が変わっていることが確認できます

さらにS3を見ると、確かにアップされている! スクリーンショット 2021-11-28 18.56.02.png

 

SAM CLIでビルド

コマンドはたったこれだけ

sam build

実行結果

(base) ~~~~~@~~~~~~~~~ sam-serverless-demo % sam build
Building codeuri: /Users/***********/sam-serverless-demo/translate-function runtime: python3.8 metadata: {} architecture: x86_64 functions: ['TranslateLambda']
requirements.txt file not found. Continuing the build without dependencies.
Running PythonPipBuilder:CopySource
Skipping copy operation since source /Users/ohsugiryoya/sam-serverless-demo/translate-function does not exist

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

.aws-sam/buildが作成され、配下に下記テンプレートファイルが作成される

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS SAM Serverless demo
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translation-function
      CodeUri: TranslateLambda
      Handler: translation-function.lambda_handler
      Runtime: python3.8
      Timeout: 5
      MemorySize: 256
      Policies:
      - TranslateFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId:
              Ref: TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api
      StageName: dev
      EndpointConfiguration: REGIONAL
  TranslateDynamoDbTbl:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: tranlate-history
      PrimaryKey:
        Name: timestamp
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1

 

先ほどと異なりCodeUriがS3リンクになっていないが、バケットとオブジェクトが作成されていました スクリーンショット 2021-11-28 19.10.57.png

 

3-3. デプロイ


デプロイコマンドで、cloudformation本来のテンプレートに変換されリソースが作成される

cloudformationコマンド実行

aws cloudformation deploy \
--template-file ./packaged-template.yaml
--stack-name serverless-sam-demo
--capabilities CAPABILITY_IAM

SAM CLIでデプロイ

インタラクティブに実行することが可能

sam deploy --guided
(base)  sam-serverless-demo % sam deploy --guided

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

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [sam-app-demo]: 
        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]: y
        #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]: y
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [Y/n]: y
	    #パブリックに公開する
        TranslateLambda may not have authorization defined, Is this okay? [y/N]: y
        Save arguments to configuration file [Y/n]: y
        SAM configuration file [samconfig.toml]: 
        SAM configuration environment [default]: 

        Looking for resources needed for deployment:
         Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-w09u3i2wjkab
         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

できた!!

スクリーンショット 2021-11-28 19.17.46.png

 

4. ローカル環境でテスト実行


SAMを使うメリットは、ローカルでテスト実行することができる点だと感じました。
lambda、api gatewayだけのようなシンプルな構成はローカルテスト可能です。
上記で作成したものはdynamoDBやtranslate apiを使用しているので、ローカル環境ではエラーがでます。

ソースコードの構文チェック

sam validate

関数をローカルで呼び出す

sam local invoke

Lambda ローカルテスト

sam local start-lambda

#別ターミナルで以下コマンド叩く
aws lambda invoke --function-name "TranslateLambda" \
--endpoint-url "http://127.0.0.1:3001" \
--no-verify-ssl out.txt

API Gateway ローカルテスト

sam local start-api

#別ターミナルで以下コマンド叩く
curl -w "\n" http://127.0.0.1:3000/translate

 

(参考)ハマりポイント


初回デプロイ時エラーからの再デプロイ

Initiating deployment
=====================
Uploading to sam-app-demo/ec906befd23684dfd9dd718c1f5d6539.template  1114 / 1114  (100.00%)
Error: Failed to create changeset for the stack: sam-app-demo, An error occurred (ValidationError) when calling the CreateChangeSet operation: Stack:arn:aws:cloudformation:ap-northeast-1:624840664351:stack/sam-app-demo/515b2930-49e5-11ec-865e-06680d75238d is in DELETE_FAILED state and can not be updated.

⇨スタックを削除してから再デプロイする

aws cloudformation delete-stack --stack-name hogehoge

FAILEDとなった時の対処法

aws cloudformation describe-stack-events \
--stack-name sam-app-demo \
| jq '.StackEvents[] \
| select(.ResourceStatus == "CREATE_FAILED") \
| .ResourceStatusReason' -r

 

まとめ


一通りSAMの基本的な使い方をまとめてみました。 ローカルデプロイはいろいろ使い道を見いだせそうですね。 今後は、実務で使う際の注意点やベストプラクティス等まとめてみたいと思います。