こんにちは。AWS CLIが好きな福島です。
- はじめに
- 参考
- そもそも、AWS SAMとは?
- AWS SAMを利用するメリット
- 概要図
- ワークショップでやったこと
- ①サンプルアプリの準備(sam init)
- ②サンプルアプリをローカルで実行(sam local)
- ③サンプルアプリのビルド(sam build)
- ④サンプルアプリのデプロイ(sam deploy)
- 終わりに
はじめに
最近、サーバレスなアーキテクチャに興味があり、 AWS SAMのワークショップを実施したため、備忘としてブログを書きたいと思います。
ちなみに、ネットや周りの人を見ると、AWS SAMではなく、Serverless Frameworkを利用している方が多い印象を受けますが、とりあえず、AWSが提供しているAWS SAMを触ってみました。
参考
そもそも、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を使ってパイプラインを組んでみたいと思います。
どなたかのお役に立てれば幸いです。