どうもこんにちは。
今回は、AWSのセミナー内でお話に出てきた、AWS SAMについて調べたのでまとめてみました。
ちなみに私、感動しております。
AWS SAMってなに?
AWS SAM (Serverless Application Model) は、サーバーレスアプリケーションをローカルで開発、テスト、デプロイするための強力なオープンソースフレームワークです。AWS SAMを使用するには、AWS SAM CLIというものをインストールする必要があります。
ちなみに、AWS SAM自体は無料で使用できます。AWS SAMを使用して作成したAPI GatewayやLambda関数に対してのみ料金が発生します。
通常、サーバーレスアプリケーションを作成するにはどうする?
通常では、以下のような構成でサーバーレスアプリケーションを構築すると思います。(最も簡単な構成)
ここに、CloudFront
やAmazon SQS
、S3
を組み込んだりすると思います。(これは一旦おいときまして。)
上記の構成を実現するのに、以下の手順を踏む必要があるはずです。
- AWSマネジメントコンソール上でDynamoDBを作成する
- AWSマネジメントコンソール上でLambda関数を作成する
- AWSマネジメントコンソール上でAPI Gatewayのメソッドを作成し、URLを発行する
これって全て、AWSマネジメントコンソール上で行ったり来たりする必要があります。(めんどくさい...)
AWS SAMのお出ましだっ!
AWS SAMを使用すると、1つのYAMLファイルに定義するだけで、勝手にLambda関数などを作ってくれます。
AWS SAMの使用方法
1. AWS SAM CLIのインストール
インストール方法は、Windows
,MacOS
,Linux
によって変わります。
以下を参照してインストールしてください。(自分はパッケージインストーラ(GUI)を使用しました。)
以下が正常に実行されたら、インストール完了です。
$ which sam
$ sam --version
2. サーバーレスアプリケーションプロジェクトの作成
ターミナルで以下を実行していきます。
$ mkdir AWS_SAM_test && cd AWS_SAM_test
$ sam init
sam init
を実行すると対話形式で必要なもの、不要なものを入力して行くことになります。
ここは1つ1つ解説します。
2-1. AWSのテンプレート or カスタムテンプレート
You can preselect a particular runtime or package type when using the `sam init` experience.
Call `sam init --help` to learn more.
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice:
初めて使うので、「1」を入力します。
2-2. どのAWSテンプレートを使う?
Choose an AWS Quick Start application template
1 - Hello World Example
2 - Data processing
3 - Hello World Example with Powertools for AWS Lambda
4 - Multi-step workflow
5 - Scheduled task
6 - Standalone function
7 - Serverless API
8 - Infrastructure event management
9 - Lambda Response Streaming
10 - Serverless Connector Hello World Example
11 - Multi-step workflow with Connectors
12 - GraphQLApi Hello World Example
13 - Full Stack
14 - Lambda EFS example
15 - DynamoDB Example
16 - Machine Learning
Template:
今回は、Lambdaを使ってみようと思うので、「1」を入力します。
2-3. どのランタイムとパッケージを使用する?
Use the most popular runtime and package type? (Python and zip) [y/N]:
デフォルトでよく使われるランタイムとパッケージタイプを提案してくれていますね。
python
とzip
を使用してくれそうなので、「y」を入力します。
2-4. アプリケーションのトレース機能を使用する?
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]:
トレース機能を使用するか聞かれています。最初は必要ないので、「N」を入力します。
2-5. CloudWatchを使用する?
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]:
CloudWatchでログのモニタリングを使用するか聞かれていますね。今回は必要ないので「N」を入力します。
2-6. 関数のログをJSON形式で出力しますか?
Would you like to set Structured Logging in JSON format on your Lambda functions? [y/N]:
関数のログを JSON 形式で出力する機能を有効にするか聞かれています。
これはどっちでも良いですが、Yesにすると追加料金がかかってしまう恐れがあるので注意が必要です。
2-7. プロジェクトの名前
Project name [sam-app]: sam-test-01
プロジェクト名を設定します。今回は、sam-test-01
とします。
2-8. 完了!
-----------------------
Generating application:
-----------------------
Name: sam-test-01
Runtime: python3.9
Architectures: x86_64
Dependency Manager: pip
Application Template: hello-world
Output Directory: .
Configuration file: sam-test-01/samconfig.toml
Next steps can be found in the README file at sam-test-01/README.md
Commands you can use next
=========================
[*] Create pipeline: cd sam-test-01 && sam pipeline init --bootstrap
[*] Validate SAM template: cd sam-test-01 && sam validate
[*] Test Function in the Cloud: cd sam-test-01 && sam sync --stack-name {stack-name} --watch
これで完了です。
3. template.yamlを編集
sam init
実行時点で、以下のファイルが作成されます。スゲーですな。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-test-01
Sample SAM Template for sam-test-01
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
MemorySize: 128
# You can add LoggingConfig parameters such as the Logformat, Log Group, and SystemLogLevel or ApplicationLogLevel. Learn more here https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-loggingconfig.
LoggingConfig:
LogFormat: JSON
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: Hello World Lambda Function ARN
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value: !GetAtt HelloWorldFunctionRole.Arn
今回は、以下のように変更します。
- Lambda関数の名前を
SamTest01Func
に変更します-
Resources.HelloWorldFunction
をResources.SamTest01Func
にします
-
- 関数のタイプアウト時間を10秒にしたいので、
Globals.Function.Timeout
の値を10にします -
Resources.SamTestFunc.Properties.Runtime
をPython3.12に変更します
4. template.yamlに問題がないか確認
sam validate
を実行すると、yamlファイルに問題がないか確認してくれます。
今回は、Lambda関数の名前をSamTest01Func
に変更したとき、他の箇所も変更を加える必要があったようでした。
% sam validate
[[E6101: Validate that outputs values are a string] ('HelloWorldFunction' is not one of ['SamTestFunc', 'SamTestFuncRole', 'SamTestFuncHelloWorldPermissionProd', 'ServerlessRestApi', 'ServerlessRestApiDeployment<>', 'ServerlessRestApiProdStage']) matched 42, [E6101: Validate that outputs values are a string] ('HelloWorldFunctionRole' is not one of ['SamTestFunc', 'SamTestFuncRole', 'SamTestFuncHelloWorldPermissionProd', 'ServerlessRestApi', 'ServerlessRestApiDeployment<>', 'ServerlessRestApiProdStage']) matched 45]
Error: Linting failed. At least one linting rule was matched to the provided template.
修正して再度挑戦!
% sam validate
/Users/testuser/code/AWS_SAM_test/sam-test-01/template.yml is a valid SAM Template
OKでした!
5. Lambda関数を編集
sam-test-01/hello_world/app.py
にというファイルが作成されているので、開きます。
コメントアウトでたくさん書かれていますが、以下のように、hello world, sam-test-01
とログが出力されるようにします。
import json
def lambda_handler(event, context):
return {
"statusCode": 200,
"body": json.dumps({
"message": "hello world, sam-test-01",
}),
}
これでプロジェクトの作成は完了です。
6. プロジェクトをローカルでビルドしてみる
sam build
を実行したらローカルでビルドできるっぽいです。
% sam build
Starting Build use cache
Manifest file is changed (new hash: <ハッシュ値>) or dependency folder (.aws-sam/deps/<何かの文字列>) is missing for (SamTestFunc), downloading
dependencies and copying/building source
Building codeuri: /Users/testuser/code/AWS_SAM_test/sam-test-01/hello_world runtime: python3.12 architecture: x86_64 functions: SamTestFunc
Running PythonPipBuilder:CleanUp
Running PythonPipBuilder:ResolveDependencies
Running PythonPipBuilder:CopySource
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
うまくいったっぽいっすね。これで、ローカルでLambda関数のテストを実行する準備ができました。
7. ローカルでテストしてみます
sam local invoke
を実行すると、Lambda関数のテストをしてくれます。
Lambda関数のテストというのは、以下のスクショの赤い四角部分のボタンを押した時に実行されるテストのことです。
実際に実行してみると、以下のようになっています。
% sam local invoke
Invoking app.lambda_handler (python3.12)
Local image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-python3.12
Building image...................................................................................................................................................................................................................................................................................................
Using local image: public.ecr.aws/lambda/python:3.12-rapid-x86_64.
Mounting /Users/testuser/code/AWS_SAM_test/sam-test-01/.aws-sam/build/SamTestFunc as /var/task:ro,delegated, inside runtime container
START RequestId: <リクエストID> Version: $LATEST
END RequestId: <リクエストID>
REPORT RequestId: <リクエストID> Init Duration: 0.26 ms Duration: 185.90 ms Billed Duration: 186 ms Memory Size: 128 MB Max Memory Used: 128 MB
{"statusCode": 200, "body": "{\"message\": \"hello world, sam-test-01\"}"}
手順5でapp.py
を修正して、hello world, sam-test-01
という文字列を出力するように修正しましたが、ちゃんと出力されていますね!
8. ローカルでWebサーバーを立ち上げる
sam local start-api
を実行するとWebサーバーが立ち上がってくれます。
% sam local start-api
Initializing the lambda functions containers.
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.12-rapid-x86_64.
Mounting /Users/testuser/code/AWS_SAM_test/sam-test-01/.aws-sam/build/SamTestFunc as /var/task:ro,delegated, inside runtime container
Containers Initialization is done.
Mounting SamTestFunc 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. 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
2024-08-31 19:02:09 WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:3000
2024-08-31 19:02:09 Press CTRL+C to quit
試しにブラウザでhttp://127.0.0.1:3000
にアクセスしてみると、以下のように表示されました。
{
"message": "Missing Authentication Token"
}
こういうものなのかな?わかる人いたら教えてください。
また、Ctrl + C
でサーバーを止めることができます。
9. Pythonコードのテストを実行
Webサーバーを立ち上げている状態であれば、python -m pytest <相対パス>
でPytestの実行もできるようです。
% python -m pytest tests/unit/test_handler.py
======================================================================== test session starts ========================================================================
platform darwin -- Python 3.11.3, pytest-8.3.2, pluggy-1.5.0
rootdir: /Users/testuser/code/AWS_SAM_test/sam-test-01
collected 1 item
tests/unit/test_handler.py . [100%]
========================================================================= 1 passed in 0.01s =========================================================================
10. AWS環境にデプロイ
sam deploy
コマンドを実行すると、デプロイしてくれます。
また、変更内容を詳しく確認したい場合は、sam deploy --guidedオプションを使って対話形式でデプロイを進めると、変更内容を一つずつ確認できます。
途中で、Deploy this changeset? [y/N]:
というメッセージが出てきますが、そのままデプロイを進める場合や「y」を入力してください。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key SamTestFunc
Description Hello World Lambda Function ARN
Value <lambdaのURL>
Key HelloWorldApi
Description API Gateway endpoint URL for Prod stage for Hello World function
Value <API GatewayのURL>
Key SamTestFuncIamRole
Description Implicit IAM Role created for Hello World function
Value <IAMロールのURL>
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - sam-test-01 in ap-northeast-1
11. API GatewayのURLへアクセス
デプロイした時にOutputsに出力されるAPI GatewayのURLに、ブラウザでアクセスします。
アクセスできたー!
ほとんど言われるがままでできちゃいました...
すげー
12. デプロイしたやつを削除する
sam delete
を実行することで、API GatewayやLambda関数を削除できます。また、自動で作成されたIAMロールやS3バケットも削除されます。
まとめ
template.yml
の書き方がマスターできれば、サーバーレスアプリケーションの構築が簡単にできてしまいますね!
また、AWS Application Composer というツールを使用すると、template.yml
をGUI上で作成することができるそうです。これは、VScodeの拡張機能AWS Toolkit for visual studio code
をインストールすることで使用することができます。
早速試してみます。別の記事で!