AWS SAMとは?
AWS SAMの概要
AWS SAMはサーバーレスアプリケーションを定義するためのシンプルなテンプレート形式を提供します。このテンプレートは、CloudFormationを拡張したものであり、Lambda関数、API Gateway、DynamoDBテーブルなどのAWSリソースを簡潔に記述できます。AWS SAMはAWS CloudFormationと統合されているため、インフラストラクチャのデプロイ、管理、バージョン管理が一貫して行えます。インフラストラクチャをコードとして扱うことで、デプロイプロセスが再現可能で信頼性が向上します。語弊があることを承知で簡単に申し上げるなら、AWS SAMはLambda関数+その他のAWSサービスを迅速に開発したり安全に管理することができるサービスと言えます。
AWS SAMを導入するメリット
簡単な処理を実装するだけであればAWSのマネジメントコンソール(AWSの画面)で十分な場合もあるかと思います。しかし、SAMを使うことで大きく2つのメリットを享受することができます。
- 迅速な開発とデプロイの実現
AWS SAMはAWS CLIとして提供されており、開発用PCのローカル環境にインストールすることでVS Codeなどの普段利用しているエディタでも開発が可能になります。特にCloud9(厳密にはEC2)にはSAMがプリインストールされているため、環境を立ち上げてからすぐにAWS SAMを利用することができます。日ごろから使用しているIDEを利用できることで開発効率(例えばデバッグ、コード解析など)を向上することができます。 - IaCによるAWSの構成管理が容易
AWS SAMではCloudFormationで利用するyamlと同様の記述が可能なため、マネジメントコンソールから各サービスごとの個別設定をせずにyamlによる一元管理が可能になります。これにより連携サービスの設定変更や追加を容易に実現することができます。
Cloud9でローカル開発環境を構築
前提
- Cloud9(OSはubuntu 22.04 LTS、インスタンスタイプはt2.micro、dockerがインストール済)
※本記事ではCloud9の環境構築は説明しません。 - Lambdaの実行環境はpython3.12
想定シーンと開発の流れ
S3にファイルをアップロード後、そのPUTイベントを検知してLambda関数を実行
プロジェクト作成
まずCloud9のターミナルを開き、下記のコマンドを実行してLambda関数を作っていきましょう。sam init
を実行するとLambda環境について設定をしていくことになります。実際にはインタラクティブモードで対話と選択肢が表示されますが、ここでは選択肢のみを記載しています。また今回は11行目のHello Worldテンプレート利用してプロジェクトsam-app
を作成することとします。
なお対話と選択肢についてはSAMのバージョンが異なると表示順や選択肢が変化することがあります。今回説明する設定はあくまで一例として参考にしてくださいね。
sam --version
SAM CLI, version 1.112.0
# samディレクトリを作成してプロジェクト作成
mkdir sam
cd sam
sam init
#以下、設定の選択肢を列挙
1 - AWS Quick Start Templates
1 - Hello World Example
Use the most popular runtime and package type? N
18 - python3.12
1 - Zip
Would you like to enable X-Ray tracing on the function(s) in your application? N
Would you like to enable monitoring using CloudWatch Application Insights? N
Would you like to set Structured Logging in JSON format on your Lambda functions? N
Project name [sam-app] sam-app
プロジェクトのフォルダ構成
では出来上がったプロジェクト構成のフォルダ構成をチェックしましょう。Cloud9のファイルシステム(ファイルやフォルダ構成が表示されているエリア)で確認が可能ですが、ここではtreeコマンドをインストールしてフォルダ構成を表示させています。
sudo apt update
sudo apt install tree
tree sam-app
sam-app
├── README.md
├── __init__.py
├── events
│ └── event.json
├── hello_world
│ ├── __init__.py
│ ├── app.py
│ └── requirements.txt
├── samconfig.toml
├── template.yaml
└── tests
├── __init__.py
├── integration
│ ├── __init__.py
│ └── test_api_gateway.py
├── requirements.txt
└── unit
├── __init__.py
└── test_handler.py
ここではローカル開発を進める上で把握しておいた方がいいファイルについて簡単に紹介します。まずはここで紹介した4つのファイルを把握しておくとよいでしょう。
- event.json(9行目)
ローカル開発をする際にイベント情報をエミュレートするためのJSONファイル - app.py(12行目)
Lambda関数の処理を記述するファイル - requirements.txt(13行目)
pythonの標準外ライブラリを利用する際に記述するファイル - template.yaml(15行目)
Lambdaとそれに連携するAWSサービス(例えばS3やAPI gatewayなど)の構成を管理するファイル
イベント情報のサンプルJSONデータ作成
Lambda関数の開発に入る前にS3のイベント情報が定義されたサンプルのJSONデータを生成していきます。2行目のコマンドを実施することでeventディレクトリ直下にS3のputイベント用jsonデータを作成することができます。開発時にはこのjsonデータ利用します。
sam local generate-event s3 put | tee events/s3-event.json
{
"Records": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "us-east-1",
"eventTime": "1970-01-01T00:00:00.000Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "EXAMPLE"
},
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"responseElements": {
"x-amz-request-id": "EXAMPLE123456789",
"x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "testConfigRule",
"bucket": {
"name": "example-bucket",
"ownerIdentity": {
"principalId": "EXAMPLE"
},
"arn": "arn:aws:s3:::example-bucket"
},
"object": {
"key": "test/key",
"size": 1024,
"eTag": "0123456789abcdef0123456789abcdef",
"sequencer": "0A1B2C3D4E5F678901"
}
}
}
]
}
Lambda関数とyamlの編集
ここまででLambda関数の開発の準備ができました。それではさっそくソースコードを改変してS3のputイベント発生時の処理を実装していきましょう。まずapp.pyを下記のように編集してください。これで実行時に出力されたログの中でHello AWS SAM
とS3のイベント情報が格納されたevent
の情報を確認することができます。
import json
def lambda_handler(event, context):
print('Hello AWS SAM')
print(json.dumps(event))
続きてtemplate.yamlを下記のように編集してください。まず11行目のTimeoutの数字を30(秒)に設定します。また22行目以降の記述は今回の実装では関係ないのでコメントアウトもしくは削除します。これで実装は完了です!
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
sam-app
Sample SAM Template for sam-app
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 30
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.12
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関数を実行していきたいと思います。まずは編集したものをビルドします。t2.microだと30秒くらいかかると思いますがしばらくお待ちください。すると3行目のようにDockerのイメージを取得しており、ローカルでの動作確認はDockerを介して行われていることがわかります。そして5行目のようにビルド成功の表示が確認できればビルドは完了です。
sam build -u
…
Fetching public.ecr.aws/sam/build-python3.12:latest-x86_64 Docker container image
…
Build Succeeded
…
最後にLambda関数の実行です。1行目のコマンドを実行するとコンテナイメージのビルドが始まり3行目以降のように実行結果が出力されます。よく見ると4行目でHello AWS SAM
が、5行目でevent
情報が出力されていることがわかります。5行目の情報はイベント情報のサンプルJSONデータ作成
で作成したJSONの中身と一致していることがわかりますね!
sam local invoke -e events/s3-event.json HelloWorldFunction
…
START RequestId: 5a2d83e0-75b7-49e8-9448-487cd699b5ca Version: $LATEST
Hello AWS SAM
{"Records": [{"eventVersion": "2.0", "eventSource": "aws:s3", "awsRegion": "us-east-1", "eventTime": "1970-01-01T00:00:00.000Z", "eventName": "ObjectCreated:Put", "userIdentity": {"principalId": "EXAMPLE"}, "requestParameters": {"sourceIPAddress": "127.0.0.1"}, "responseElements": {"x-amz-request-id": "EXAMPLE123456789", "x-amz-id-2": "EXAMPLE123/5678abcdefghijklambdaisawesome/mnopqrstuvwxyzABCDEFGH"}, "s3": {"s3SchemaVersion": "1.0", "configurationId": "testConfigRule", "bucket": {"name": "example-bucket", "ownerIdentity": {"principalId": "EXAMPLE"}, "arn": "arn:aws:s3:::example-bucket"}, "object": {"key": "test/key", "size": 1024, "eTag": "0123456789abcdef0123456789abcdef", "sequencer": "0A1B2C3D4E5F678901"}}}]}
END RequestId: b59356c5-19c8-4395-88a1-aef42b4a930c
REPORT RequestId: b59356c5-19c8-4395-88a1-aef42b4a930c Init Duration: 0.03 ms Duration: 190.81 ms Billed Duration: 191 ms Memory Size: 128 MB Max Memory Used: 128 MB
null
ここまでくればあとはevents/s3-event.jsonのイベント情報やhello_world/app.pyを編集することでLambda関数の実装&デバッグを進めていくことができますね!
まとめ
今回はAWS SAMを利用したLambdaのローカル開発環境の構築について解説しました。本記事を通じてAWS SAMの利用で案外簡単に開発環境が構築できることを体験頂けたら幸いです!また別の記事にてAWS SAMを利用したサーバーレスアプリケーションの構成管理も解説しますのでそちらもご参考くださいね!