【AWS SAM】入門してみた

記事タイトルとURLをコピーする

こんにちは。AWS CLIが好きな福島です。

はじめに

最近、サーバレスなアーキテクチャに興味があり、 AWS SAMのワークショップを実施したため、備忘としてブログを書きたいと思います。

ちなみに、ネットや周りの人を見ると、AWS SAMではなく、Serverless Frameworkを利用している方が多い印象を受けますが、とりあえず、AWSが提供しているAWS SAMを触ってみました。

参考

catalog.workshops.aws

そもそも、AWS SAMとは?

一言でいうと、CloudFormationの拡張機能でサーバレス開発に便利な機能かなと思います。

また、AWS SAMには、専用のCLIが用意されており、基本的にはこのCLIを使い、SAMを利用します。

AWS SAMを利用するメリット

  • CloudFormationに比べ、API GatewayやLambdaといったサーバレスなサービスの設定を容易に定義可能
  • ローカルでの構築、テスト、およびデバッグが可能

など

概要図

ワークショップでやったこと

ここからは、ワークショップでやったことを記載していきます。

①サンプルアプリの準備(sam init)
②サンプルアプリをローカルで実行(sam local)
③サンプルアプリのビルド(sam build)
④サンプルアプリのデプロイ(sam deploy)

①サンプルアプリの準備(sam init)

  • 実行コマンド

以下のコマンドを実行すると、対話形式になるため、適宜回答していきます。

sam init
  • 実行例
# sam init

You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.

// サンプルのテンプレートを利用するか、自分が用意したテンプレートを利用するか、指定できます。
// 今回は、サンプルのテンプレートを利用するため、「1」を選択しています。
Which template source would you like to use?
        1 - AWS Quick Start Templates
        2 - Custom Template Location
Choice: 1

// 複数のサンプルアプリの中から選択ができるのですが、今回は「1」を選択しています。
Choose an AWS Quick Start application template
        1 - Hello World Example
        2 - Multi-step workflow
        3 - Serverless API
        4 - Scheduled task
        5 - Standalone function
        6 - Data processing
        7 - Infrastructure event management
        8 - Serverless Connector Hello World Example
        9 - Multi-step workflow with Connectors
        10 - Lambda EFS example
        11 - Machine Learning
Template: 1

// 最新のPython+パッケージのタイプがZipで良いか聞かれます。
// 今回はそれでいいのですが、あえて「いいえ(N)」を選択しています。
Use the most popular runtime and package type? (Python and zip) [y/N]:

// 利用するランタイムを聞かれます。
// 今回は、python3.9を利用するため、「16」を選択します。
Which runtime would you like to use?
        1 - aot.dotnet7 (provided.al2)
        2 - dotnet6
        3 - dotnet5.0
        4 - dotnetcore3.1
        5 - go1.x
        6 - go (provided.al2)
        7 - graalvm.java11 (provided.al2)
        8 - graalvm.java17 (provided.al2)
        9 - java11
        10 - java8.al2
        11 - java8
        12 - nodejs18.x
        13 - nodejs16.x
        14 - nodejs14.x
        15 - nodejs12.x
        16 - python3.9
        17 - python3.8
        18 - python3.7
        19 - ruby2.7
        20 - rust (provided.al2)
Runtime: 16

// パケージタイプを聞かれます。
// Zip形式のため、「1」を選択します。
What package type would you like to use?
        1 - Zip
        2 - Image
Package type: 1

Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.

// X-Rayを有効化するか聞かれますが、不要なため、「いいえ(N)」を選択します。
Would you like to enable X-Ray tracing on the function(s) in your application?  [y/N]:

// CloudWatch Application Insightsを有効化するか聞かれますが、不要なため、「いいえ(N)」を選択します。
Would you like to enable monitoring using CloudWatch Application Insights?
For more info, please view https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cloudwatch-application-insights.html [y/N]:

// サンプルアプリの名前を聞かれます。
// 今回は、デフォルトの「sam-app」とします。
Project name [sam-app]:

// GitHubからClone
Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)

    -----------------------
    Generating application:
    -----------------------
    Name: sam-app
    Runtime: python3.9
    Architectures: x86_64
    Dependency Manager: pip
    Application Template: hello-world
    Output Directory: .

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

// 次に実行可能なコマンド例が表示されます。
Commands you can use next
=========================
[*] Create pipeline: cd sam-app && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-app && sam validate
[*] Test Function in the Cloud: cd sam-app && sam sync --stack-name {stack-name} --watch

#

コマンドの実行が完了すると、以下のフォルダおよびファイルが生成(GitHubからClone)されます。

# ls -lRa sam-app/
sam-app/:
total 40
drwxr-xr-x 5 root root 4096 Apr  5 10:46 .
drwxr-xr-x 3 root root 4096 Apr  5 10:46 ..
-rw-r--r-- 1 root root 3730 Apr  5 10:46 .gitignore
-rw-r--r-- 1 root root 8349 Apr  5 10:46 README.md
-rw-r--r-- 1 root root    0 Apr  5 10:46 __init__.py
drwxr-xr-x 2 root root 4096 Apr  5 10:46 events
drwxr-xr-x 2 root root 4096 Apr  5 10:46 hello_world
-rw-r--r-- 1 root root 1681 Apr  5 10:46 template.yaml
drwxr-xr-x 4 root root 4096 Apr  5 10:46 tests

sam-app/events:
total 12
drwxr-xr-x 2 root root 4096 Apr  5 10:46 .
drwxr-xr-x 5 root root 4096 Apr  5 10:46 ..
-rw-r--r-- 1 root root 1968 Apr  5 10:46 event.json

sam-app/hello_world:
total 16
drwxr-xr-x 2 root root 4096 Apr  5 10:46 .
drwxr-xr-x 5 root root 4096 Apr  5 10:46 ..
-rw-r--r-- 1 root root    0 Apr  5 10:46 __init__.py
-rw-r--r-- 1 root root 1151 Apr  5 10:46 app.py
-rw-r--r-- 1 root root    8 Apr  5 10:46 requirements.txt

sam-app/tests:
total 20
drwxr-xr-x 4 root root 4096 Apr  5 10:46 .
drwxr-xr-x 5 root root 4096 Apr  5 10:46 ..
-rw-r--r-- 1 root root    0 Apr  5 10:46 __init__.py
drwxr-xr-x 2 root root 4096 Apr  5 10:46 integration
-rw-r--r-- 1 root root   22 Apr  5 10:46 requirements.txt
drwxr-xr-x 2 root root 4096 Apr  5 10:46 unit

sam-app/tests/integration:
total 12
drwxr-xr-x 2 root root 4096 Apr  5 10:46 .
drwxr-xr-x 4 root root 4096 Apr  5 10:46 ..
-rw-r--r-- 1 root root    0 Apr  5 10:46 __init__.py
-rw-r--r-- 1 root root 1488 Apr  5 10:46 test_api_gateway.py

sam-app/tests/unit:
total 12
drwxr-xr-x 2 root root 4096 Apr  5 10:46 .
drwxr-xr-x 4 root root 4096 Apr  5 10:46 ..
-rw-r--r-- 1 root root    0 Apr  5 10:46 __init__.py
-rw-r--r-- 1 root root 2527 Apr  5 10:46 test_handler.py
#

上記の中からいくつかファイルの説明を以下に記載いたします。

sam-app/template.yaml      : SAMのテンプレートファイル
sam-app/hello_world/app.py : Lambdaにデプロイするコード
sam-app/events/event.json  : sam localでテスト実行する際に利用できるテストイベント

②サンプルアプリをローカルで実行(sam local)

このコマンドを実行するためには、Dockerが稼働している必要があります。

  • Lambdaのテストを行うコマンド
sam local invoke --event events/event.json
  • 実行例
# sam local invoke --event events/event.json
Invoking app.lambda_handler (python3.9)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.9-rapid-x86_64.

Mounting /root/sam/sam-app/hello_world as /var/task:ro,delegated inside runtime container
START RequestId: 158b211e-6ea4-4a1a-8af9-ed7968fe7b99 Version: $LATEST
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}END RequestId: 158b211e-6ea4-4a1a-8af9-ed7968fe7b99
REPORT RequestId: 158b211e-6ea4-4a1a-8af9-ed7968fe7b99  Init Duration: 1.08 ms  Duration: 180.23 ms     Billed Duration: 181 ms Memory Size: 128 MB     Max Memory Used: 128 MB
#

改行がされていないため少し見づらいですが、下から2行目のところでステータスコードが200と 「hello world」のメッセージが出力されていることが分かります。

  • API Gatewayをシミュレートするローカル HTTP サーバーを起動するコマンド
# sam local start-api --port 8080
  • 実行例

2つのターミナルA,Bを利用します。

// ターミナルAで実行
# sam local start-api --port 8080
Mounting HelloWorldFunction at http://127.0.0.1:8080/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. If you used sam build before running local commands, you will need to re-run sam build for the changes to be picked up. You only need to restart SAM CLI if you update your AWS SAM template
2023-04-05 13:13:49  * Running on http://127.0.0.1:8080/ (Press CTRL+C to quit)

// ターミナルBでcurlを実行
# curl -s http://127.0.0.1:8080/hello
{"message": "hello world"}
#

// ターミナルAで以下のようにアクセスログが出力されます。
Invoking app.lambda_handler (python3.9)
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.9-rapid-x86_64.

Mounting /root/sam/sam-app/hello_world as /var/task:ro,delegated inside runtime container
START RequestId: 0e5a489f-9f9a-4715-b17e-f5e3628be860 Version: $LATEST
END RequestId: 0e5a489f-9f9a-4715-b17e-f5e3628be860
REPORT RequestId: 0e5a489f-9f9a-4715-b17e-f5e3628be860  Init Duration: 0.51 ms  Duration: 271.65 ms     Billed Duration: 272 ms Memory Size: 128 MB     Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2023-04-05 13:14:14 127.0.0.1 - - [05/Apr/2023 13:14:14] "GET /hello HTTP/1.1" 200 -

// ターミナルBでLambdaのコードを変更し、Curlを実行します。
 #  sed -i 's/hello world/hello my friend/g' sam-app/hello_world/app.py
 #  curl -s http://127.0.0.1:8080/hello
{"message": "hello my friend"} 
#

// ターミナルAで再度以下のようにアクセスログが出力されます。
Invoking app.lambda_handler (python3.9)
Using local image: public.ecr.aws/lambda/python:3.9-rapid-x86_64.

Mounting /root/sam/sam-app/hello_world as /var/task:ro,delegated inside runtime container
START RequestId: 18af5bab-f8e2-47ff-9583-082ce5945da5 Version: $LATEST
END RequestId: 18af5bab-f8e2-47ff-9583-082ce5945da5
REPORT RequestId: 18af5bab-f8e2-47ff-9583-082ce5945da5  Init Duration: 0.09 ms  Duration: 83.69 ms      Billed Duration: 84 ms  Memory Size: 128 MB     Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2023-04-05 13:39:14 127.0.0.1 - - [05/Apr/2023 13:39:14] "GET /hello HTTP/1.1" 200 -

上記の実行例の通り、アプリが実行中にLambdaのコードを変更した場合、 アプリの再起動なしでコードが反映されるため、より開発がしやすくいのかなと存じます。

③サンプルアプリのビルド(sam build)

  • 実行コマンド
sam build
  • 実行例
# sam build
Building codeuri: /root/sam/sam-app/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource

Build Succeeded

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

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided
#

ビルドコマンドの実行結果に表示されているように、ビルドを実行すると、 .aws-sam/buildに成果物が生成されます。

ポイントとしては、「.aws-sam/build/HelloWorldFunction」配下にLambdaで必要な(requirements.txtに記載した)モジュールがダウンロードされていることが分かります。

# ls -lrt .aws-sam/build
total 8
-rw-r--r--  1 root root 1112 Apr  5 13:44 template.yaml
drwxr-xr-x 13 root root 4096 Apr  5 13:44 HelloWorldFunction
#
# ls -lrt .aws-sam/build/HelloWorldFunction
total 52
-rw-r--r-- 1 root root    8 Apr  5 10:46 requirements.txt
-rw-r--r-- 1 root root    0 Apr  5 10:46 __init__.py
-rw-r--r-- 1 root root 1155 Apr  5 13:39 app.py 
drwxr-xr-x 2 root root 4096 Apr  5 13:44 charset_normalizer.libs
drwxr-xr-x 5 root root 4096 Apr  5 13:44 urllib3
drwxr-xr-x 2 root root 4096 Apr  5 13:44 charset_normalizer-3.1.0.dist-info
drwxr-xr-x 4 root root 4096 Apr  5 13:44 charset_normalizer
drwxr-xr-x 2 root root 4096 Apr  5 13:44 urllib3-1.26.15.dist-info
drwxr-xr-x 2 root root 4096 Apr  5 13:44 requests-2.28.2.dist-info
drwxr-xr-x 2 root root 4096 Apr  5 13:44 requests
drwxr-xr-x 2 root root 4096 Apr  5 13:44 idna-3.4.dist-info
drwxr-xr-x 2 root root 4096 Apr  5 13:44 idna
drwxr-xr-x 2 root root 4096 Apr  5 13:44 certifi-2022.12.7.dist-info
drwxr-xr-x 2 root root 4096 Apr  5 13:44 certifi
#

④サンプルアプリのデプロイ(sam deploy)

  • 実行コマンド
sam deploy --guided
  • 実行例
# sam deploy --guided

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

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

        Setting default arguments for 'sam deploy'
        =========================================
        // CloudFormationがデプロイされるため、スタック名を指定します。(今回はデフォルトのsam-appにしています。)
        Stack Name [sam-app]:
        // デプロイするリージョンを指定します。
        AWS Region [ap-northeast-1]:
        // デプロイする前に変更セットを確認するか聞かれます。今回は「Yes(y)」にしました。
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [y/N]: y
        // SAMが利用するIAMロールを作成していいか聞かれます。必要なため、デフォルトの「Yes(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]:
        // デプロイが途中で失敗した場合、ロールバックアップを無効化するか聞かれます。ロールバックして欲しいため、デフォルトの「No(N)」にしてます。
        #Preserves the state of previously provisioned resources when an operation fails
        Disable rollback [y/N]:
        // Lambdaの関数に権限がないけど、問題ないか聞かれます。問題ないため、「Yes(y)」にしてます。
        HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
        // デプロイオプションをコンフィグファイルに保存するか聞かれます。次回以降のデプロイが簡素化されるため、「Yes(y)」にしてます。
        Save arguments to configuration file [Y/n]:
        // デプロイオプションを定義するファイル名が聞かれます。今回はデフォルトの「samconfig.toml」にしています。
        SAM configuration file [samconfig.toml]:
        // コンフィグごとに名前を付けられるのですが、今回はデフォルトの「default」にしています。
        SAM configuration environment [default]:

        Looking for resources needed for deployment:
         Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-119107g070xjh
         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/8aaa7331daf4a4bdbf651c33610617f0  619841 / 619841  (100.00%)

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

Initiating deployment
=====================
Uploading to sam-app/98a323c690f49366d440ec83884d02ec.template  1200 / 1200  (100.00%)

Waiting for changeset to be created..
CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Operation                                                           LogicalResourceId                                                   ResourceType                                                        Replacement
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ Add                                                               HelloWorldFunctionHelloWorldPermissionProd                          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:012345678912:changeSet/samcli-deploy1680671612/61d1ace0-1b02-4b55-9051-c4a231da5718


Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2023-04-05 14:13:44 - Waiting for stack create/update to complete

CloudFormation events from stack operations (refresh every 0.5 seconds)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                                                      ResourceType                                                        LogicalResourceId                                                   ResourceStatusReason
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                                                  AWS::CloudFormation::Stack                                          sam-app                                                             User Initiated
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::ApiGateway::Deployment                                         ServerlessRestApiDeployment47fc2d5f9d                               -
CREATE_IN_PROGRESS                                                  AWS::Lambda::Permission                                             HelloWorldFunctionHelloWorldPermissionProd                          -
CREATE_IN_PROGRESS                                                  AWS::Lambda::Permission                                             HelloWorldFunctionHelloWorldPermissionProd                          Resource creation Initiated
CREATE_IN_PROGRESS                                                  AWS::ApiGateway::Deployment                                         ServerlessRestApiDeployment47fc2d5f9d                               Resource creation Initiated
CREATE_COMPLETE                                                     AWS::ApiGateway::Deployment                                         ServerlessRestApiDeployment47fc2d5f9d                               -
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                                             HelloWorldFunctionHelloWorldPermissionProd                          -
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::012345678912:role/sam-app-HelloWorldFunctionRole-ODWIQ7DOHL0I

Key                 HelloWorldApi
Description         API Gateway endpoint URL for Prod stage for Hello World function
Value               https://w3rpjxw1dc.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/

Key                 HelloWorldFunction
Description         Hello World Lambda Function ARN
Value               arn:aws:lambda:ap-northeast-1:012345678912:function:sam-app-HelloWorldFunction-A1LgpFrAV7fX
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

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


#

実行結果として、Outputs欄にHelloWorldApiが出力されているため、そのValue(API Gatewayのエンドポイント)に対して、Curlを実行します。

# curl -s https://w3rpjxw1dc.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message": "hello my friend"} 
#

終わりに

今回は、AWS SAMのワークショップを実施したため、備忘としてブログにまとめました。 次回はSAMを使ってパイプラインを組んでみたいと思います。

どなたかのお役に立てれば幸いです。

福島 和弥 (記事一覧)

2019/10 入社

AWS CLIが好きです。

AWS資格12冠。2023 Japan AWS Partner Ambassador/APN ALL AWS Certifications Engineer。