開発中に AWS Lambda 関数をローカル環境で実行するなら AWS SAM CLI の sam local invoke -e event.json
コマンドを使えば良く,また AWS Lambda 関数のベストプラクティスに載っている Lambda ハンドラーをコアロジックから分離します。
を意識して実装すれば,単体テストを軸に動作確認を進めることもできる.
とは言え,実際に AWS Lambda 関数のイベントソースマッピング(トリガー設定)を確認したいこともあり,今回は AWS SAM を使って構築する Amazon SQS キューと AWS Lambda 関数の組み合わせを samlocal
コマンドを使って LocalStack にデプロイして動作確認をしてみた.結果的に期待した通りに動いた❗️
\( 'ω')/ LocalStack 便利すぎ〜
🚀 アーキテクチャ図
🚀 検証環境
template.yaml
検証に使った AWS SAM テンプレート(AWS CloudFormation テンプレート)を以下に載せておく.特別なことはなく AWS::SQS::Queue
と AWS::Serverless::Function
を構築して,イベントソースマッピングを設定してある.ランタイムは何でも良く,今回は Python 3.9 にしてある.
AWSTemplateFormatVersion: 2010-09-09 Transform: AWS::Serverless-2016-10-31 Resources: Queue: Type: AWS::SQS::Queue Properties: QueueName: kakakakakku-queue ReceiveMessageWaitTimeSeconds: 20 Function: Type: AWS::Serverless::Function Properties: FunctionName: kakakakakku-function CodeUri: app/ Handler: app.lambda_handler Runtime: python3.9 Architectures: - x86_64 Events: SqsEvent: Type: SQS Properties: Queue: !GetAtt Queue.Arn
app/app.py
AWS Lambda 関数で動かす Python コードはあくまで必要最低限にして,Amazon SQS キューのメッセージをログ出力(AWS CloudWatch Logs)している🐍
def lambda_handler(event, context): for record in event['Records']: print(record['body'])
GitHub にも置いておいた💡
🚀 samlocal
コマンドを準備する
今回は AWS SAM (AWS CloudFormation) と LocalStack を組み合わせるため,LocalStack AWS CLI (awslocal
コマンド) に加えて AWS SAM CLI for LocalStack (samlocal
コマンド) をセットアップしておく.samlocal --version
コマンドを実行して,通常の sam
コマンドにバイパスされていれば OK❗️
$ pip install aws-sam-cli-local $ samlocal --version SAM CLI, version 1.81.0
🚀 LocalStack にデプロイする
次はさっそく LocalStack にデプロイする.AWS SAM CLI を使ったことがあれば「今まで通り」と言えば伝わると思う.sam
コマンドではなく samlocal
コマンドに置き換えて,あとは同じく build
と deploy
を実行する❗️すると samlocal
コマンドによって,LocalStack にデプロイできる.
samlocal deploy
コマンドの実行結果をできる限りそのまま載せておく.見慣れたログではあるけど,最後の arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1682430872/b79df315
を見て「ああ!LocalStack にデプロイしてたんだ!」と気付くレベル✌️
samconfig.toml
を作る- AWS SAM 専用の Amazon S3 バケットを作る
- 今回だと
aws-sam-cli-managed-default-samclisourcebucket-055e11c4
- 今回だと
- AWS リソースを作る
- AWS::SQS::Queue
- AWS::Lambda::Function
- AWS::IAM::Role
- AWS::Lambda::EventSourceMapping
$ export DEFAULT_REGION=ap-northeast-1 $ samlocal build $ samlocal deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Not found Setting default arguments for 'sam deploy' ========================================= Stack Name [sam-app]: sandbox-app 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]: #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]: #Preserves the state of previously provisioned resources when an operation fails Disable rollback [y/N]: Save arguments to configuration file [Y/n]: SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Looking for resources needed for deployment: Creating the required resources... Successfully created! Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-055e11c4 A different default S3 bucket can be set in samconfig.toml and auto resolution of buckets turned off by setting resolve_s3=False 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 sandbox-app/62f50535d41ccb37bda86914d0d680f3 405 / 405 (100.00%) Deploying with following values =============================== Stack name : sandbox-app Region : ap-northeast-1 Confirm changeset : False Disable rollback : False Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-055e11c4 Capabilities : ["CAPABILITY_IAM"] Parameter overrides : {} Signing Profiles : {} Initiating deployment ===================== Uploading to sandbox-app/12ff669083061914f8a1286e9c315653.template 781 / 781 (100.00%) Waiting for changeset to be created.. CloudFormation stack changeset ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType Replacement ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + Add Queue AWS::SQS::Queue N/A + Add Function AWS::Lambda::Function N/A + Add FunctionRole AWS::IAM::Role N/A + Add FunctionSqsEvent AWS::Lambda::EventSourceMapping N/A ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1682430872/b79df315 2023-04-25 00:00:00 - Waiting for stack create/update to complete CloudFormation events from stack operations (refresh every 5.0 seconds) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ResourceStatus ResourceType LogicalResourceId ResourceStatusReason ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- CREATE_COMPLETE AWS::SQS::Queue Queue - CREATE_COMPLETE AWS::IAM::Role FunctionRole - CREATE_COMPLETE AWS::Lambda::Function Function - CREATE_COMPLETE AWS::Lambda::EventSourceMapping FunctionSqsEvent - CREATE_COMPLETE AWS::CloudFormation::Stack sandbox-app - ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Successfully created/updated stack - sandbox-app in ap-northeast-1
🚀 デプロイ結果を確認する
awslocal
コマンドを使って LocalStack にデプロイされた AWS リソースを確認する(日付は適当にマスキングしてある).
Amazon SQS キュー
$ awslocal sqs list-queues { "QueueUrls": [ "http://localhost:4566/000000000000/kakakakakku-queue" ] }
AWS Lambda 関数
$ awslocal lambda list-functions { "Functions": [ { "FunctionName": "kakakakakku-function", "FunctionArn": "arn:aws:lambda:ap-northeast-1:000000000000:function:kakakakakku-function", "Runtime": "python3.9", "Role": "arn:aws:iam::000000000000:role/sandbox-app-FunctionRole-c5268ca9", "Handler": "app.lambda_handler", "CodeSize": 405, "Description": "", "Timeout": 3, "MemorySize": 128, "LastModified": "2023-04-25T00:00:00.000000+09:00", "CodeSha256": "fpUHNomors6Sbn3Ii0zpVUYGBpzxbmxSXB950QZmisg=", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "ee14fbd2-1412-431b-b615-7c87676f4330", "PackageType": "Zip", "Architectures": [ "x86_64" ], "EphemeralStorage": { "Size": 512 }, "SnapStart": { "ApplyOn": "None", "OptimizationStatus": "Off" } } ] }
AWS Lambda 関数(イベントソースマッピング)
$ awslocal lambda list-event-source-mappings { "EventSourceMappings": [ { "UUID": "98e14881-4802-4e3d-be48-ffdf6766a455", "BatchSize": 10, "MaximumBatchingWindowInSeconds": 0, "EventSourceArn": "arn:aws:sqs:ap-northeast-1:000000000000:kakakakakku-queue", "FunctionArn": "arn:aws:lambda:ap-northeast-1:000000000000:function:kakakakakku-function", "LastModified": "2023-04-25T00:00:00.000000+09:00", "State": "Enabled", "StateTransitionReason": "USER_INITIATED", "FunctionResponseTypes": [] } ] }
Amazon S3 バケット
$ awslocal s3api list-buckets { "Buckets": [ { "Name": "aws-sam-cli-managed-default-samclisourcebucket-055e11c4", "CreationDate": "2023-04-25T00:00:00+00:00" }, { "Name": "awslambda-ap-northeast-1-tasks", "CreationDate": "2023-04-25T00:00:00+00:00" } ], "Owner": { "DisplayName": "webfile", "ID": "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a" } }
Amazon CloudWatch Logs ロググループ
Amazon CloudWatch Logs ロググループは AWS SAM (AWS CloudFormation) で構築していないので1個もなくて OK👌この後 AWS Lambda 関数を実行してログを確認するため,実行前の状況を確認しておきたかった.
$ awslocal logs describe-log-groups { "logGroups": [] }
🚀 動作確認をする
次は awslocal
コマンドを使って Amazon SQS キューにメッセージを送信して,AWS Lambda 関数のイベントソースマッピングの動作確認をする.
$ MESSAGE='{ "my-key": "my-value" }' $ awslocal sqs send-message --queue-url http://localhost:4566/000000000000/kakakakakku-queue --message-body ${MESSAGE} { "MD5OfMessageBody": "3234172c8554dd70c6b2dbaac5acf11e", "MessageId": "678a5cd4-8849-4969-bbd7-0b9df93703d3" }
すると Amazon CloudWatch Logs ロググループに "{ \"my-key\": \"my-value\" }"
というログを確認できて,期待通り AWS Lambda 関数が実行されたことがわかる❗️
$ awslocal logs describe-log-groups { "logGroups": [ { "logGroupName": "/aws/lambda/kakakakakku-function", "creationTime": 1682431237731, "metricFilterCount": 0, "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/kakakakakku-function:*", "storedBytes": 286 } ] } $ awslocal logs describe-log-streams --log-group-name /aws/lambda/kakakakakku-function { "logStreams": [ { "logStreamName": "2023/04/25/[$LATEST]fe281c36f2654eb40cce1a30fbcfd8eb", "creationTime": 1682431237736, "firstEventTimestamp": 1682431237714, "lastEventTimestamp": 1682431237728, "lastIngestionTime": 1682431237742, "uploadSequenceToken": "1", "arn": "arn:aws:logs:ap-northeast-1:000000000000:log-group:/aws/lambda/kakakakakku-function:log-stream:2023/04/25/[$LATEST]fe281c36f2654eb40cce1a30fbcfd8eb", "storedBytes": 286 } ] } $ awslocal logs get-log-events --log-group-name /aws/lambda/kakakakakku-function --log-stream-name '2023/04/25/[$LATEST]fe281c36f2654eb40cce1a30fbcfd8eb' { "events": [ { "timestamp": 1682431237714, "message": "START RequestId: 93a8f37b-5d8b-4c96-81fc-4e7bc3d3239e Version: $LATEST", "ingestionTime": 1682431237742 }, { "timestamp": 1682431237718, "message": "{ \"my-key\": \"my-value\" }", "ingestionTime": 1682431237742 }, { "timestamp": 1682431237723, "message": "END RequestId: 93a8f37b-5d8b-4c96-81fc-4e7bc3d3239e", "ingestionTime": 1682431237742 }, { "timestamp": 1682431237728, "message": "REPORT RequestId: 93a8f37b-5d8b-4c96-81fc-4e7bc3d3239e\tDuration: 13.08 ms\tBilled Duration: 14 ms\tMemory Size: 128 MB\tMax Memory Used: 128 MB\t", "ingestionTime": 1682431237742 } ], "nextForwardToken": "f/00000000000000000000000000000000000000000000000000000003", "nextBackwardToken": "b/00000000000000000000000000000000000000000000000000000000" }
もちろん AWS CloudFormation スタック sandbox-app
もできあがっている✌️
$ awslocal cloudformation list-stacks { "StackSummaries": [ { "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-sam-cli-managed-default/5f4cfa71", "StackName": "aws-sam-cli-managed-default", "CreationTime": "2023-04-25T00:00:00.000000+00:00", "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00", "StackStatus": "CREATE_COMPLETE", "DriftInformation": { "StackDriftStatus": "NOT_CHECKED" } }, { "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/sandbox-app/d0a1ffad", "StackName": "sandbox-app", "CreationTime": "2023-04-25T00:00:00.000000+00:00", "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00", "StackStatus": "CREATE_COMPLETE", "DriftInformation": { "StackDriftStatus": "NOT_CHECKED" } } ] }
🚀 お掃除
使わなくなったら awslocal cloudformation delete-stack
コマンドで AWS CloudFormation スタックを削除できる.ちゃんと削除後は StackStatus が DELETE_COMPLETE
になっている.
$ awslocal cloudformation delete-stack --stack-name sandbox-app $ awslocal cloudformation list-stacks { "StackSummaries": [ { "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/aws-sam-cli-managed-default/5f4cfa71", "StackName": "aws-sam-cli-managed-default", "CreationTime": "2023-04-25T00:00:00.000000+00:00", "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00", "StackStatus": "CREATE_COMPLETE", "DriftInformation": { "StackDriftStatus": "NOT_CHECKED" } }, { "StackId": "arn:aws:cloudformation:ap-northeast-1:000000000000:stack/sandbox-app/d0a1ffad", "StackName": "sandbox-app", "CreationTime": "2023-04-25T00:00:00.000000+00:00", "LastUpdatedTime": "2023-04-25T00:00:00.000000+00:00", "DeletionTime": "2023-04-25T00:00:00.000000+00:00", "StackStatus": "DELETE_COMPLETE", "DriftInformation": { "StackDriftStatus": "NOT_CHECKED" } } ] } $ awslocal lambda list-functions { "Functions": [] }
🚀 まとめ
Amazon SQS キューと AWS Lambda 関数の組み合わせなど「イベントソースマッピング(トリガー設定)」の動作確認をローカル環境で行うために samlocal
コマンドを使って LocalStack にデプロイしてみた.最終的には LocalStack でサポートされている API 次第ではあるけど,今回の簡単なシナリオでは期待通りに動いた❗️
ちなみに LocalStack を使うときは,基本 awslocal
コマンドを使うけど,LocalStack Web Application の Resource Browser を使うと,一部の AWS リソースであれば画面から確認できて便利なときもある❗️最初はウェブサイトからどうやってローカル環境の LocalStack にアクセスしてるんだろ?と疑問だったけど,ちょっと調べてみたら https://localhost.localstack.cloud:4566/
に対して API を呼び出す仕組みになっていた💨
\( 'ω')/ あ〜 LocalStack 便利〜