AWS SAMとLocalStackを使って、簡単にクラウドとローカルにデプロイする
はじめに
AWS SAMを使えば、サーバレスの開発がサクッとできて便利です。
ですが、少し凝ったことをするときはローカルでテストを行いたいことが多々あります。
そういった場合には、Localstackを利用する方が多いと思うのですが、SAMをどうやってLocalstackにデプロイするのか一瞬考えると思います。
lambdaであれば、zipで固めたものをLocakstackにデプロイしてもいいですが、他にも利用しているサービスがあった場合は面倒です。
そこで、aws-sam-cli-localを利用してみたら結構便利だったので、備忘録として残します。
やりたいこと
sam init
で作成したプロジェクトを、sam deploy
と同じようなコマンドで、Localstackにデプロイしたい。
環境
本記事での環境に利用した環境は以下の通りです。
- mac book pro 16(2019)
- mac OS Monterey 12.5.1
- Docker Desktop 4.16.2
- SAM CLI, version 1.79.0
- Local stack community 1.4.0
完成品
完成したコードは、こちらのリポジトリで公開しています。
本題
では、実際にaws-sam-cli-localを利用して、Localstackにデプロイする環境を構築していきましょう。
今回は、サンプルプログラム Hello World をデプロイしてみようと思います。
環境構築
sam でサンプルプロジェクト Hello World を構築
まず、samとlocalstackのDockerfileを保存するためのディレクトリを作成します。
# sam と localstackの設定を保存するディレクトリを作成
$ mkdir sam-project
$ cd sam-project
次に、サンプルプロジェクトを作成していきます。
# samでプロジェクトを作成
$ sam init
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
Hello World Example を選択します。
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 - Hello World Example With Powertools
8 - Infrastructure event management
9 - Serverless Connector Hello World Example
10 - Multi-step workflow with Connectors
11 - Lambda EFS example
12 - DynamoDB Example
13 - Machine Learning
Template: 1
今回は、個人的な趣味でnodejs18.xを利用します。
Use the most popular runtime and package type? (Python and zip) [y/N]:
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 - python3.10
20 - ruby2.7
21 - rust (provided.al2)
Runtime: 12
packageのタイプは、Zipを選択して下さい。
Imageを選択してしまうと、aws-sam-local-cliでのデプロイ時に失敗します。
What package type would you like to use?
1 - Zip
2 - Image
Package type: 1
今回はJavascriptを選択しました。(TypeScriptでも問題ないと思います)
Based on your selections, the only dependency manager available is npm.
We will proceed copying the template using npm.
Select your starter template
1 - Hello World Example
2 - Hello World Example TypeScript
Template: 1
X-Rayは不要なのでインストールは行いません。
Would you like to enable X-Ray tracing on the function(s) in your application? [y/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]:
後は、プロジェクトネームを入力して終了です。
Project name [sam-app]: hello-world
Cloning from https://github.com/aws/aws-sam-cli-app-templates (process may take a moment)
-----------------------
Generating application:
-----------------------
Name: hello-world
Runtime: nodejs18.x
Architectures: x86_64
Dependency Manager: npm
Application Template: hello-world
Output Directory: .
Configuration file: hello-world/samconfig.toml
Next steps can be found in the README file at hello-world/README.md
Commands you can use next
=========================
[*] Create pipeline: cd hello-world && sam pipeline init --bootstrap
[*] Validate SAM template: cd hello-world && sam validate
[*] Test Function in the Cloud: cd hello-world && sam sync --stack-name {stack-name} --watch
aws-sam-cli-local をインストール
samlocal deploy
を実行するだけで、localstackへデプロイを行いたいので、aws-sam-cli-local をインストールします。
このパッケージを動かすには、pythonが必要なので、pipenvで環境を構築してインストールします。
$ pipenv --python 3.9
$ pipenv install aws-sam-cli-local
localstackの環境を構築
環境を汚したく無いので、localstackはdocker-composeを利用して動かします。
profileの準備
localstackで利用するプロファイルを準備しましょう。(この記事では特に必要ないですが、あった方が便利です)
まず、設定ファイルを格納するディレクトリを準備します。
$ mkdir -p docker/settings/profile
# profileに必要なファイルをファイルを作成
$ touch docker/settings/profile/config
$ touch docker/setting/profile/credentials
後は、以下の記述をそれぞれのファイルに記述して下さい。
[profile localstack]
region = us-east-1
output = json
[localstack]
aws_access_key_id = dummy
aws_secret_access_key = dummy
compose.yamlの準備
次に、compose.yamlを作成します。
$ touch compose.yaml
以下の設定をcompose.yamlに記載します。
ここで重要なのでは、localstack1.4.0を利用することです。
2.0以上のバージョンを利用すると、cloudformationを利用するには有料版(Pro)を利用してね!って出てきます(cloudformationも有料版限定になったんですかね?ドキュメント読む限りでは変更されてないはずなんですが・・・)
services:
localstack:
container_name: "${LOCALSTACK_DOCKER_NAME:-localstack_main}"
image: localstack/localstack:1.4.0
configs:
- source: aws_profile
target: /root/.aws
ports:
- "127.0.0.1:4566:4566" # LocalStack Gateway
- "127.0.0.1:4510-4559:4510-4559" # external services port range
environment:
- DEBUG=${DEBUG:-0}
- LAMBDA_EXECUTOR=${LAMBDA_EXECUTOR:-docker-reuse}
- PROVIDER_OVERRIDE_LAMBDA=asf # enable runtime node.js 18.x
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- "${LOCALSTACK_VOLUME_DIR:-./volume}:/var/lib/localstack"
- "/var/run/docker.sock:/var/run/docker.sock"
configs:
aws_profile:
file: ./docker/settings/profile
AWSへサンプルプロジェクト Hello Worldのデプロイ
せっかくなので、作成した Hello World プロジェクトをデプロイしてみましょう。
Hello World のビルド
まず、ビルドしましょう。
$ sam build
ビルドに成功すると、以下のように表示されます。
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
Hello World のデプロイ
それでは、AWSにデプロイしましょう。
以下のコマンドを実行します。
※デフォルトの設定だとAPI GatewayはPublic(認証が設定されていない)なので注意して下さい。
$ sam deploy
デプロイの前準備が完了すると、以下のように聞かれるので、y を入力して下さい。
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
デプロイが正常に完了すると、以下のように結果が出力されます。
CloudFormation outputs from deployed stack
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value arn:aws:iam::*************:role/hello-world-HelloWorldFunctionRole-6424RVTUI0FK
Key HelloWorldApi
Description API Gateway endpoint URL for Prod stage for Hello World function
Value https://ijo53fvme5.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:*************:function:hello-world-HelloWorldFunction-AwwoJ7wiNUIz
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - hello-world in ap-northeast-1
APIへのアクセス
早速、デプロイしたAPIを叩いてみましょう。
以下のようにコマンドを実行すると、無事にレスポンスが返ってくることが確認できます。
$ curl https://ijo53fvme5.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
{"message":"hello world"}
Hello Worldの削除
PublicでAPIを解放しておくのは怖いので、リソースを全て削除しておきます。
リソースを削除してもよいかと聞いてくるので、両方ともyを入力して削除します。
$ sam delete
Are you sure you want to delete the stack hello-world in the region ap-northeast-1 ? [y/N]: y
Do you want to delete the template file 611597fa35f8a2c9dd32e39f1b1b5a88.template in S3? [y/N]: y
- Deleting S3 object with key 5e3a92ff23df6d2dc4d4f08846f18326
- Deleting S3 object with key 611597fa35f8a2c9dd32e39f1b1b5a88.template
- Deleting Cloudformation stack hello-world
Deleted successfully
上記のコマンドを実行しても、aws-sam-cli-managed-default というスタックだけは消えません。
これが不要な場合は、CloudFormationのコンソールから手動で削除して下さい。
localstackへのデプロイ
それでは、本命のlocalstackにデプロイします。
pipenvのshellに入って、samlocal deploy
を実行するだけです。
# samlocalコマンドを利用するので、pipenvのshellに入る
$ pipenv shell
# localstackにデプロイ
$ samlocal deploy
Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-d00eacc7
A different default S3 bucket can be set in samconfig.toml
Or by specifying --s3-bucket explicitly.
Uploading to 5e3a92ff23df6d2dc4d4f08846f18326 565189 / 565189 (100.00%)
Deploying with following values
===============================
Stack name : hello-world
Region : ap-northeast-1
Confirm changeset : True
Disable rollback : False
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-d00eacc7
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
Initiating deployment
=====================
Uploading to c3b9a99c53e505d7a2990d04e3cfe9d3.template 1175 / 1175 (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 ServerlessRestApiProdStage AWS::ApiGateway::Stage N/A
+ Add ServerlessRestApiDeployment47fc2d5f9d AWS::ApiGateway::Deployment N/A
+ Add ServerlessRestApi AWS::ApiGateway::RestApi N/A
+ Add HelloWorldFunction AWS::Lambda::Function N/A
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:000000000000:changeSet/samcli-deploy1680994057/5fec67f8
AWSへデプロイする時と同様に、デプロイしてよいか?と聞かれるので y を入力して下さい。
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y
デプロイが完了すると、以下のようにAPIのエンドポイントを確認することができます。
CloudFormation outputs from deployed stack
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Outputs
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Key HelloWorldApi
Description API Gateway endpoint URL for Prod stage for Hello World function
Value https://yut38v0htj.execute-api.amazonaws.com:4566/Prod/hello/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:000000000000:function:hello-world-HelloWorldFunction-f6ad045a
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value arn:aws:iam::000000000000:role/hello-world-HelloWorldFunctionRole-5bbbddd8
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - hello-world in ap-northeast-1
ここまできたら、後はhttps://yut38v0htj.execute-api.amazonaws.com:4566/Prod/hello/
を叩くだけです!
と言いたいのですが、このエンドポイントは嘘です。信じないでください。
localstackでAPI Gatewayのエンドポイントを叩く場合は、以下のように読み替える必要があります。
- https://yut38v0htj.execute-api.amazonaws.com:4566/Prod/hello/
+ http://yut38v0htj.execute-api.localhost.localstack.cloud:4566/Prod/hello/
読み替えた状態で、以下のようにエンドポイントを叩けば、無事にレスポンスが返ってきます。
$ curl http://yut38v0htj.execute-api.localhost.localstack.cloud:4566/Prod/hello/
{"message":"hello world"}
まとめ
ということで、AWS SAM + Localstack + aws-sam-cli-local を使って、Hello Worldのデプロイをやってみました。
以前までは、localstackを起動して、S3バケットを作って、zipで固めて、Lambdaをデプロイして、API Gate Wayを作成して・・・と原始人スタイルで開発していたので結構大変でしたが、aws-sam-cli-localを使うことで簡単にデプロイできることが確認できました。
この程度であれば、sam local start-api
を実行するだけでよいですが、S3などを利用したい場合は一気に楽になると思います。
もっとリッチな構成でテストを行う場合は、LocalStack Proを利用する必要性がありますが、構成次第ではCommunity でも十分だと思います。
Discussion