AWS SAMを試してみる
以下の続きで今度はAWS SAM
前提
前提は前回と同じ。
以下を参考にdevcontainerを作った。
https://zenn.dev/nmemoto/articles/using-aws-cdk-and-aws-sam-with-remote-containers
githubのテンプレートレポジトリにしている。
https://github.com/kun432/devcontainer-aws-cdk-sam
最初のサイトにworkspace周りの設定が含まれているが、ここはちょっと自分でハマってみたいので、一旦設定は入れてない。
とりあえず上記テンプレートレポジトリからレポジトリを作って、vscode devcontainerで作業することとする。足りなければ適宜編集していく。
なお、dockerはremote development で使用しているサーバ上で動かしている。Docker Destktopではないので注意。
SAMのワークショップ
動画じゃなくてドキュメントでほしい・・・
詳細は上のworkshopを参考に。
冒頭でプロジェクトディレクトリを作成しているが、gitレポジトリのルートをプロジェクトディレクトリとして使いたいのでスキップする。
s3バケット作成
$ aws s3 mb s3://aws-sam-sample-2023508
翻訳用Lambdaのディレクトリとファイルを作成
$ mkdir translate-function
$ touch translate-function/translate-function.py
SAMのテンプレートファイルを作成
$ touch template.yaml
それぞれ以下の内容で作成する。
import json
import logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event, context):
logger.info(event)
return {
'statusCode': 200,
'body': json.dumps('Hello Hands on world!')
}
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
TranslateLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: translate-function-2
CodeUri: ./translate-function
Handler: translate-function.lambda_handler
Runtime: python3.7
Timeout: 5
MemorySize: 256
SAMのテンプレートのリファレンスはここにある
ではこれらをCloudFormationのパッケージにしていく
$ aws cloudformation package \
--template-file template.yaml \
--s3-bucket aws-sam-sample-2023508 \
--output-template-file packaged-template.yaml
出力
Uploading to d33d23482e788e1ff1e5bf734af8de98 310 / 310.0 (100.00%)
Successfully packaged artifacts and wrote output template to file packaged-template.yaml.
Execute the following command to deploy the packaged template
aws cloudformation deploy --template-file /workspaces/aws-sam-sample/packaged-template.yaml --stack-name <YOUR STACK NAME>
packaged-template.yaml
が生成される。中身はこんな感じ。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
TranslateLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: translate-function-2
CodeUri: s3://aws-sam-sample-2023508/d33d23482e788e1ff1e5bf734af8de98
Handler: translate-function.lambda_handler
Runtime: python3.7
Timeout: 5
MemorySize: 256
CodeUri
がS3に置き換わっているのがわかる。ここにLambdaのソースが置かれるのだと思う。
で先ほど実行したコマンドの出力結果に出ているdeployのコマンドを実行すればデプロイされるということになるが、ワークショップ内で指定されているコマンドは以下となっていた。
$ aws cloudformation deploy \
--template-file ./packaged-template.yaml \
--stack-name hands-on-serverless-2 \
--capabilities CAPABILITY_IAM
--template-file
は相対なのか絶対なのかの違いだけなのでおいておく。--capabilities CAPABILITY_IAM
はCloudFormationからIAMの操作が必要となるため付与する必要がある。
ということで実行した出力結果。
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - hands-on-serverless-2
作成された模様。
さらに上記のLambdaからAmazon Translateを使えるようにSAMテンプレートを修正して、Lambdaのコードも変更する。
まずLambdaのコード。
import json
import boto3
translate = boto3.client('translate')
def lambda_handler(event, context):
input_text = "こんにちは。ご機嫌いかがですか?"
response = translate.translate_text(
Text=input_text,
SourceLanguageCode='ja',
TargetLanguageCode='en'
)
output_text = response.get('TranslatedText')
return {
'statusCode': 200,
'body': json.dumps({
'output_text': output_text
})
}
boto3を入れてなかったので入れておく。
boto3
$ pip install -r requirements.txt
次にSAMのテンプレート。こちらは大きく変わったわけではなくて、最後にIAMのマネージドポリシーをアタッチしてTranslateにアクセスできるようになっている。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
TranslateLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: translate-function-2
CodeUri: ./translate-function
Handler: translate-function.lambda_handler
Runtime: python3.7
Timeout: 5
MemorySize: 256
# 以下を追加
Policies:
- TranslateFullAccess
ではパッケージ化してデプロイする。
$ aws cloudformation package \
--template-file template.yaml \
--s3-bucket aws-sam-sample-2023508 \
--output-template-file packaged-template.yaml
$ aws cloudformation deploy \
--template-file ./packaged-template.yaml \
--stack-name hands-on-serverless-2 \
--capabilities CAPABILITY_IAM
テストしてみると、変更したものがデプロイされ正常に動いていることがわかる。
では次にAPI Gatewayを前段に配置してWeb APIとしてアクセスできるようにするように変更していく。
まずLambda。クエリパラメータを受けてTranslateに渡してその結果を返すというものになった。
import json
import boto3
translate = boto3.client(service_name='translate')
def lambda_handler(event, context):
input_text = event['queryStringParameters']['input_text']
response = translate.translate_text(
Text=input_text,
SourceLanguageCode="ja",
TargetLanguageCode="en"
)
output_text = response.get('TranslatedText')
return {
'statusCode': 200,
'body': json.dumps({
'output_text': output_text
}),
'isBase64Encoded': False,
'headers': {}
}
次にSAMテンプレート。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
TranslateLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: translate-function-2
CodeUri: ./translate-function
Handler: translate-function.lambda_handler
Runtime: python3.7
Timeout: 5
MemorySize: 256
Policies:
- TranslateFullAccess
# 以下を追加
Events:
GetApi:
Type: Api
Properties:
Path: /translate
Method: get
RestApiId: !Ref TranslateAPI
TranslateAPI:
Type: AWS::Serverless::Api
Properties:
Name: translate-api-2
StageName: dev
EndpointConfiguration: REGIONAL
Translate APIって書いてあるからAmazon Translateのリソース設定かと一瞬思ったけど、AWS::Serverless::ApiとあるのでこれがAPI Gatewayのことらしい。EventsがLambdaとAPI Gatewayを紐付けるために必要なプロパティで、!Ref
でリソース間の依存関係を指定するのはCloudFormationと同じ。
ではパッケージ化してデプロイ。
$ aws cloudformation package \
--template-file template.yaml \
--s3-bucket aws-sam-sample-2023508 \
--output-template-file packaged-template.yaml
$ aws cloudformation deploy \
--template-file ./packaged-template.yaml \
--stack-name hands-on-serverless-2 \
--capabilities CAPABILITY_IAM
API Gatewayが作成されている・Lambdaと紐付いている・Lambdaのコードが更新されている、ことを確認したら、ブラウザからAPI Gatewayのエンドポイントにアクセスしてみる。
https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんばんはー、今日は冷えますね。
結果
{"output_text": "Good evening, it's going to be cold today."}
ちゃんと動いていることが確認できた。
さらにDynamoDBを追加してリクエストの履歴をDynamoDBに保存するようにしていく。
Lambdaのコードは以下。詳細は割愛。
import json
import boto3
import datetime
translate = boto3.client(service_name='translate')
dynamodb_translate_history_tbl = boto3.resource('dynamodb').Table('translate-history-2')
def lambda_handler(event, context):
input_text = event['queryStringParameters']['input_text']
response = translate.translate_text(
Text=input_text,
SourceLanguageCode="ja",
TargetLanguageCode="en"
)
output_text = response.get('TranslatedText')
dynamodb_translate_history_tbl.put_item(
Item = {
"timestamp": datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
"input": input_text,
"output": output_text
}
)
return {
'statusCode': 200,
'body': json.dumps({
'output_text': output_text
}),
'isBase64Encoded': False,
'headers': {}
}
SAMテンプレートは以下。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
TranslateLambda:
Type: AWS::Serverless::Function
Properties:
FunctionName: translate-function-2
CodeUri: ./translate-function
Handler: translate-function.lambda_handler
Runtime: python3.7
Timeout: 5
MemorySize: 256
Policies:
- TranslateFullAccess
- AmazonDynamoDBFullAccess # 追加
Events:
GetApi:
Type: Api
Properties:
Path: /translate
Method: get
RestApiId: !Ref TranslateAPI
TranslateAPI:
Type: AWS::Serverless::Api
Properties:
Name: translate-api-2
StageName: dev
EndpointConfiguration: REGIONAL
# 以下を追加
TranslateDynamoDbTbl:
Type: AWS::Serverless::SimpleTable
Properties:
TableName: translate-history-2
PrimaryKey:
Name: timestamp
Type: String
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
DynamoDBテーブルリソースを追加してLambdaに権限を与えるという感じ。
再度パッケージ化してデプロイ。
$ aws cloudformation package \
--template-file template.yaml \
--s3-bucket aws-sam-sample-2023508 \
--output-template-file packaged-template.yaml
$ aws cloudformation deploy \
--template-file ./packaged-template.yaml \
--stack-name hands-on-serverless-2 \
--capabilities CAPABILITY_IAM
ブラウザからアクセスしてみる
https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/Stage/translate?input_text=こんばんはー、今日は冷えますね。
ちゃんとレスポンスが返ってきたことを確認しつつ、DynamoDBを見てみるとテーブルが作成されていて、リクエストの内容が保存されていることがわかる。
ここまでで一旦完了、ということで、作成したリソースを削除していく。
ここまでのやり方だとaws-cliを使っているので、aws cloudformation delete-stack
になると思うけどまあ今回はマネージメントコンソールから削除する。
- CloudFormationで"hands-on-serverless-2"スタックを削除。これでLambda・API Gateway・DynamoDB・その他IAMロールなどが削除される。
- S3は削除されないので中身を空にして削除する。
SAM CLIを使う
ここまでのやり方だとSAMはCloudFormationの簡易版っていうぐらいでそこまで便利とは思えなかった。おそらくSAM CLIを使うと変わるのだと思う。ということでやっていく。
新しくレポジトリは用意した。
SAM CLIは予めdevcontainerに入れてあるのでスキップ。Dockerのインストールも言われているけど、最新のドキュメントにはそのあたりの記載がない。ただDocker-from-Dockerもdevcontainerで用意してあるのでおそらく大丈夫ではないかなと。
$ sam --version
SAM CLI, version 1.82.0
$ docker --version
Docker version 20.10.24+azure-1, build 297e1284d3bd092e9bc96076c3ddc4bb33f8c7ab
$ python --version
Python 3.9.16
ではプロジェクトの初期化
$ sam init
設定は対話形式で行われるので、順に設定していく。質問内容が以前とは変わっている模様。以下は参考までに。python3.10を選びたかったけどruntimeが対応していない様子なので3.9で。(Imageだったらできるのかな?)
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 - Hello World Example With Powertools
8 - Infrastructure event management
9 - Serverless Connector Hello World Example
10 - Multi-step workflow with Connectors
11 - Lambda Response Streaming
12 - Lambda EFS example
13 - DynamoDB Example
14 - Machine Learning
Template: 1 # 1を選択
Use the most popular runtime and package type? (Python and zip) [y/N]: N # 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 - java17
10 - java11
11 - java8.al2
12 - java8
13 - nodejs18.x
14 - nodejs16.x
15 - nodejs14.x
16 - nodejs12.x
17 - python3.9
18 - python3.8
19 - python3.7
20 - python3.10
21 - ruby2.7
22 - rust (provided.al2)
Runtime: 17 # 17を選択
What package type would you like to use?
1 - Zip
2 - Image
Package type: 1 # 1を選択
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: N # Bを選択
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]: N # Nを選択
Project name [sam-app]: # デフォルトのまま
以下のようにプロジェクトの設定が表示される。
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: .
Configuration file: sam-app/samconfig.toml
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
で、プロジェクトディレクトリが作成される。
$ ls -a
. .. .devcontainer .git .gitignore README.md sam-app .vscode
$ tree -a sam-app/
sam-app/
├── events
│ └── event.json
├── .gitignore
├── hello_world
│ ├── app.py
│ ├── __init__.py
│ └── requirements.txt
├── __init__.py
├── README.md
├── samconfig.toml
├── template.yaml
└── tests
├── __init__.py
├── integration
│ ├── __init__.py
│ └── test_api_gateway.py
├── requirements.txt
└── unit
├── __init__.py
└── test_handler.py
5 directories, 15 files
SAMのテンプレートやLambdaのコードも用意されている。テスト用のコードとかも見える。
CDKもそうだけど新しくディレクトリが切られるのね。ちょっとdevcontainerのディレクトリ構成を考えたほうがいいのかな?一旦そのへんはおいておいて。
プロジェクトディレクトリに移動。
$ cd sam-app
ファイルは一通り揃っているので、一旦このタイミングでファイルの内容を検証する。
$ sam validate
以下のように表示されればOK
/workspaces/aws-sam-cli-sample/sam-app/template.yaml is a valid SAM Template
パッケージを作成する
$ sam build
"Build Succeeded"となっていればいけてるっぽい。
Starting Build use cache
Manifest file is changed (new hash: 3298f13049d19cffaa37ca931dd4d421) or dependency folder (.aws-sam/deps/5f7d2a7a-b6ad-48cf-bde2-b6932e5a9197) is missing for (HelloWorldFunction), downloading dependencies and copying/building source
Building codeuri: /workspaces/aws-sam-cli-sample/sam-app/hello_world runtime: python3.9 metadata: {} architecture: x86_64 functions: HelloWorldFunction
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
ではデプロイ。
$ sam deploy --guided
色々対話形式で出てくるので順に答えていく。とりあえずよくわからないものもあるので今回は以下のような感じにした。
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Found
Reading default arguments : Success
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-app]:
AWS Region [ap-northeast-1]: ap-northeast-1
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [Y/n]: 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]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
しばらく待っていると以下のような確認が行われるので"y"ですすめる。
CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-----------------------------------------------------------------------------------------------------------------------------------------
+ Add HelloWorldFunctionHelloWorldPerm AWS::Lambda::Permission N/A
issionProd
+ Add HelloWorldFunctionRole AWS::IAM::Role N/A
+ Add HelloWorldFunction AWS::Lambda::Function N/A
+ Add ServerlessRestApiDeployment47fc2 AWS::ApiGateway::Deployment N/A
d5f9d
+ Add ServerlessRestApiProdStage AWS::ApiGateway::Stage N/A
+ Add ServerlessRestApi AWS::ApiGateway::RestApi N/A
-----------------------------------------------------------------------------------------------------------------------------------------
Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:XXXXXXXXXXXX:changeSet/samcli-deploy1683539264/deb801d3-94a5-4abb-9807-d47bae3d9ae5
Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]:
リソースが作成されていく
CloudFormation events from stack operations (refresh every 5.0 seconds)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus ResourceType LogicalResourceId ResourceStatusReason
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole -
CREATE_IN_PROGRESS AWS::IAM::Role HelloWorldFunctionRole Resource creation Initiated
CREATE_COMPLETE AWS::IAM::Role HelloWorldFunctionRole -
(snip)
完了するとこんな感じで表示される。
CloudFormation outputs from deployed stack
-------------------------------------------------------------------------------------------------------------------------------------------
Outputs
-------------------------------------------------------------------------------------------------------------------------------------------
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value arn:aws:iam::XXXXXXXXXXXX:role/sam-app-HelloWorldFunctionRole-1315DUBYI6ZW
Key HelloWorldApi
Description API Gateway endpoint URL for Prod stage for Hello World function
Value https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:sam-app-HelloWorldFunction-HckQCM18lmkr
-------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - sam-app in ap-northeast-1
ということで、API GatewayからLambdaが応答するかためしてみる。ブラウザからアクセス。
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello
ちゃんと応答している。
{"message": "hello world"}
で、これは実際にAWS上にデプロイした形だがローカルでも確認ができる。
$ sam local start-lambda
実行してみるとこうなる。
Initializing the lambda functions containers.
Local image was not found.
Removing rapid images for repo public.ecr.aws/sam/emulation-python3.9
Building image...Lambda functions containers initialization failed because of Credentials store docker-credential-dev-containers-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx exited with "".
Error: Lambda functions containers initialization failed
でこれはチョットよくわからないのだが、devcontainer内の以下が悪さをしている様子。
{
"credsStore": "dev-containers-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
これを削除するかリネームしてしまう。今回はリネームした。
$ mv ~/.docker/config.json ~/.docker/config.json_BAK
もう一度実行してみる。
$ sam local start-lambda
お、立ち上がってきた。
2023-05-08 10:09:22 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:3001
2023-05-08 10:09:22 Press CTRL+C to quit
もう一つターミナルを開いて直接Lambdaを叩いてみる。
aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt
以下のレスポンスが返ってくればOKとある。
{
"StatusCode": 200
}
でサーバが立ち上がっている方のコンソールにも以下のようにリクエストが来ていることがわかるが・・・
2023-05-08 10:17:45,830 | Invoking app.lambda_handler (python3.9)
(snip)
2023-05-08 10:18:05,923 | Timed out while attempting to establish a connection to the container. You can increase this timeout by setting the SAM_CLI_CONTAINER_CONNECTION_TIMEOUT environment variable. The current timeout is 20.0 (seconds).
2023-05-08 10:18:05 127.0.0.1 - - [08/May/2023 10:18:05] "POST /2015-03-31/functions/HelloWorldFunction/invocations HTTP/1.1" 200 -
なんかタイムアウトしているみたい。SAM_CLI_CONTAINER_CONNECTION_TIMEOUTを増やしてもダメだった。
やはり以下の記事にあるのと同じ状態になる模様。
ということで、.devcontainer/devcontainer.json
を修正する。
"remoteUser": "vscode",
"workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
"workspaceFolder": "${localWorkspaceFolder}",
再ビルドするとdevcontainerではworkspaceのパスが変わっているし、sam local start-lambdaで立ち上がるLambdaコンテナ側もマウントパスは正しいのだが、それでもタイムアウトしてしまう。。。
色々やってみたがLinux上のDockerだとダメなのかもしれない(上の記事や他の記事を見てもDocker Desktop for Win/Macになっている)。なんとなくhost.docker.internalがこの辺をよしなにやってくれてるのかなという気がしている。
MacのDocker Desktopで再度ためしてみる。
MacのDocker Desktopで同じことをやってみた。結論からいうと問題なし。
$ sam local start-lambda --container-host host.docker.internal
$ aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt
{
"StatusCode": 200
}
タイム・アウトしてない。
Invoking app.lambda_handler (python3.9)
Reuse the created warm container for Lambda function 'HelloWorldFunction'
Lambda function 'HelloWorldFunction' is already running
END RequestId: 65e4328e-0706-431b-a076-89988d1ce3f1
REPORT RequestId: 65e4328e-0706-431b-a076-89988d1ce3f1 Init Duration: 0.25 ms Duration: 122.47 ms Billed Duration: 123 ms Memory Size: 128 MB Max Memory Used: 128 MB
2023-05-09 03:29:51 127.0.0.1 - - [09/May/2023 03:29:51] "POST /2015-03-31/functions/HelloWorldFunction/invocations HTTP/1.1" 200 -
こちらも。
$ sam local invoke HelloWorldFunction --no-event --container-host host.docker.internal
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 /Users/kun432/repository/aws-sam-cli-sample/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated, inside runtime container
START RequestId: 717df814-f6af-42c5-9e69-652433a8f8e4 Version: $LATEST
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}END RequestId: 717df814-f6af-42c5-9e69-652433a8f8e4
REPORT RequestId: 717df814-f6af-42c5-9e69-652433a8f8e4 Init Duration: 0.25 ms Duration: 118.08 ms Billed Duration: 119 ms Memory Size: 128 MB Max Memory Used: 128 MB
うーん、やっぱりDocker Desktopが良しなにやってくれてる気がするなぁ。host.docker.internal
ってのが重要なのかなと。
このへんなのかな。
うーん、シンプルにdevcontainerだけで出来てるのでdocker-composeに書き換えるというのはなぁ・・・かといってメインマシンを買い換えるというのもやりたくない(そろそろそういう時期ではあるのだけど。)まあdocker-composeに書き換えれば、ほぼどこでも動くだろうし。落ち着いたらやる。
削除はsam delete
があった。
$ sam delete
Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
Are you sure you want to delete the folder sam-app in S3 which contains the artifacts? [y/N]: y
- Deleting S3 object with key sam-app/52182b25e6a404d6c7e9f18a8cf85d8f
- Deleting S3 object with key sam-app/f48532e228cf6c9d3df7f931b59f17b8.template
- Deleting Cloudformation stack sam-app
Deleted successfully
まとめ
- YAMLだけなのでTerraformとかCloudFormationとかと感覚的には同じで、そこにアプリのコードが含まれるって感じ。CDKと比べるとだいぶ違う。
- ローカルでテストできるのは便利そう。Docker Desktopじゃなくて、Dockerサーバを使う場合はもう少し確認が必要。
- DynamoDB使う場合はDynamoDB-Localを使うことになる
- この辺のネットワーク周りを考えるとやはりdocker-compose化しちゃうのが良さげ。
個人的にはサーバレスで完結させるなら、CDK使わなくてもSAMで良い気がしたけど、監視とかそういうのを考え出すとやはりIaC的なものが欲しくなる。
組み合わせってこういうことなのかな?
SAMでコンテナイメージも使えるのでやってみる。
$ sam init
違いはruntimeとpackage typeのところだけ。
Use the most popular runtime and package type? (Python and zip) [y/N]: 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 - java17
10 - java11
11 - java8.al2
12 - java8
13 - nodejs18.x
14 - nodejs16.x
15 - nodejs14.x
16 - nodejs12.x
17 - python3.9
18 - python3.8
19 - python3.7
20 - python3.10
21 - ruby2.7
22 - rust (provided.al2)
Runtime: 17
What package type would you like to use?
1 - Zip
2 - Image
Package type: 2
Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.
ディレクトリに移動
$ cd sam-app
$ tree -a
.
├── events
│ └── event.json
├── .gitignore
├── hello_world
│ ├── app.py
│ ├── Dockerfile
│ ├── __init__.py
│ └── requirements.txt
├── __init__.py
├── README.md
├── samconfig.toml
├── template.yaml
└── tests
├── __init__.py
└── unit
├── __init__.py
└── test_handler.py
4 directories, 13 files
Dockerfileとrequirements.txtがあるのがわかる。
FROM public.ecr.aws/lambda/python:3.9
COPY requirements.txt ./
RUN python3.9 -m pip install -r requirements.txt -t .
COPY app.py ./
# Command can be overwritten by providing a different command in the template directly.
CMD ["app.lambda_handler"]
request
SAMテンプレートのLambdaの部分はこう。PackageTypeとMetadataでDocker周りの設定がされているのがわかる。
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:
PackageType: Image
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
Metadata:
Dockerfile: Dockerfile
DockerContext: ./hello_world
DockerTag: python3.9-v1
パッケージを作成してみる。
$ sam build
Dockerでビルドもやってくれる。
SAM CLI now collects telemetry to better understand customer needs.
You can OPT OUT and disable telemetry collection by setting the
environment variable SAM_CLI_TELEMETRY=0 in your shell.
Thanks for your help!
Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html
Building codeuri: /Users/kun432/repository/aws-sam-cli-sample/sam-app runtime: None metadata: {'Dockerfile': 'Dockerfile', 'DockerContext': '/Users/kun432/repository/aws-sam-cli-sample/sam-app/hello_world', 'DockerTag': 'python3.9-v1'} architecture: x86_64 functions: HelloWorldFunction
Building image for HelloWorldFunction function
Setting DockerBuildArgs: {} for HelloWorldFunction function
Step 1/5 : FROM public.ecr.aws/lambda/python:3.9
3.9: Pulling from lambda/python
Status: Downloaded newer image for public.ecr.aws/lambda/python:3.9 ---> 4acb7f05d221
Step 2/5 : COPY requirements.txt ./
---> cf338165fbd4
Step 3/5 : RUN python3.9 -m pip install -r requirements.txt -t .
---> Running in 36837a0d1597
Collecting requests
Downloading requests-2.30.0-py3-none-any.whl (62 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.5/62.5 KB 1.3 MB/s eta 0:00:00
Collecting certifi>=2017.4.17
Downloading certifi-2023.5.7-py3-none-any.whl (156 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 157.0/157.0 KB 7.7 MB/s eta 0:00:00
Collecting charset-normalizer<4,>=2
Downloading charset_normalizer-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (199 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 199.2/199.2 KB 12.7 MB/s eta 0:00:00
Collecting urllib3<3,>=1.21.1
Downloading urllib3-2.0.2-py3-none-any.whl (123 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 123.2/123.2 KB 6.4 MB/s eta 0:00:00
Collecting idna<4,>=2.5
Downloading idna-3.4-py3-none-any.whl (61 kB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.5/61.5 KB 5.2 MB/s eta 0:00:00
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2023.5.7 charset-normalizer-3.1.0 idna-3.4 requests-2.30.0 urllib3-2.0.2
WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
WARNING: You are using pip version 22.0.4; however, version 23.1.2 is available.
You should consider upgrading via the '/var/lang/bin/python3.9 -m pip install --upgrade pip' command.
Removing intermediate container 36837a0d1597
---> 5292ab3aefdb
Step 4/5 : COPY app.py ./
---> 841d720fb5d7
Step 5/5 : CMD ["app.lambda_handler"]
---> Running in 15e4870eba67
Removing intermediate container 15e4870eba67
---> 6b71f8e85521
Successfully built 6b71f8e85521
Successfully tagged helloworldfunction:python3.9-v1
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
まずはローカルでためしてみる
$ sam local invoke --container-host host.docker.internal
Invoking Container created from helloworldfunction:python3.9-v1
Local image was not found.
Removing rapid images for repo helloworldfunction
Building image.................
Using local image: helloworldfunction:rapid-x86_64.
START RequestId: deaf8365-b843-43fd-a54a-dfcc8be57114 Version: $LATEST
{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}END RequestId: deaf8365-b843-43fd-a54a-dfcc8be57114
REPORT RequestId: deaf8365-b843-43fd-a54a-dfcc8be57114 Init Duration: 0.40 ms Duration: 165.12 ms Billed Duration: 166 ms Memory Size: 128 MB Max Memory Used: 128 MB
デプロイする。以前はECRも自分で作らないといけなかったようだが、今は作ってくれるらしい。
$ sam deploy --guided
こういう感じで設定。ドキュメント見る限り、ECRについても聞いてくるとあるのだが、何も聞かれなかった。
PackageType: Image で宣言された関数またはレイヤーリソースがアプリケーションに含まれる場合、AWS SAM CLI を使用して、必要な Amazon Elastic Container Registry (Amazon ECR) リポジトリを自動的に作成することができます。このリポジトリを AWS SAM CLI で作成するには、--resolve-image-repos オプションまたは --guided オプションのいずれかを使用して、その後のプロンプトに Y で応答します。
Configuring SAM deploy
======================
Looking for config file [samconfig.toml] : Found
Reading default arguments : Success
Setting default arguments for 'sam deploy'
=========================================
Stack Name [sam-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]: 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]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
イメージがビルドされているのがわかる
85b5b030b35b: Pushed
663927b9dabd: Pushed
d4168391b5c8: Pushed
091e7273b536: Pushed
a4d4ba764b31: Pushed
2d244e0816c6: Pushed
ac6a33d11b17: Pushed
84ea14de468a: Pushed
9e50b5c2a61f: Pushed
helloworldfunction-6b71f8e85521-python3.9-v1: digest: sha256:d0a030aa050fef9b4f7003abedfbf47c81ff692e8df302b992b1863bf400f9ae size: 2206
ECRが作成されているようだが、
Deploying with following values
===============================
Stack name : sam-app
Region : ap-northeast-1
Confirm changeset : True
Disable rollback : False
Deployment image repository :
{
"HelloWorldFunction": "XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/samapp7427b055/helloworldfunction19d43fc4repo"
}
Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-1ij83f43psag0
Capabilities : ["CAPABILITY_IAM"]
Parameter overrides : {}
Signing Profiles : {}
ChangeSetにECRは含まれていないように見える。
CloudFormation stack changeset
-----------------------------------------------------------------------------------------------------------------------------------------
Operation LogicalResourceId ResourceType Replacement
-----------------------------------------------------------------------------------------------------------------------------------------
+ Add HelloWorldFunctionHelloWorldPerm AWS::Lambda::Permission N/A
issionProd
+ Add HelloWorldFunctionRole AWS::IAM::Role N/A
+ Add HelloWorldFunction AWS::Lambda::Function N/A
+ Add ServerlessRestApiDeployment47fc2 AWS::ApiGateway::Deployment N/A
d5f9d
+ Add ServerlessRestApiProdStage AWS::ApiGateway::Stage N/A
+ Add ServerlessRestApi AWS::ApiGateway::RestApi N/A
-----------------------------------------------------------------------------------------------------------------------------------------
ECRに作成されていた。
削除してみる
$ sam delete
なんか聞いてくる。
Are you sure you want to delete the stack sam-app in the region ap-northeast-1 ? [y/N]: y
Found ECR Companion Stack sam-app-7427b055-CompanionStack
Do you want to delete the ECR companion stack sam-app-7427b055-CompanionStack in the region ap-northeast-1 ? [y/N]:
なるほど、メインのCloudFormationスタック以外にcompanionスタックという形で作成されるのか。
ECRはここで管理されている。
進めてみると再度確認される。
ECR repository samapp7427b055/helloworldfunction19d43fc4repo may not be empty. Do you want to delete the repository and all the images in it ? [y/N]:
更に進めると削除される。
- Deleting ECR repository samapp7427b055/helloworldfunction19d43fc4repo
- Deleting ECR Companion Stack sam-app-7427b055-CompanionStack
- Deleting Cloudformation stack sam-app
--guided
で何も聞かれなかったのだけが気になる。コードを見る限りは聞いてきても良さそうなものだけど。
複数の環境
色々方針はあると思うけど、とりあえず以下のような感じがいいかなと思っている。
- 本番(Prod)/開発(Dev)の2つに分ける
- 全部分ける。
- 例えばAPI Gatewayはステージで分けることもできるし、Lambdaならエイリアス/バージョニングで分けることができる。
- が、リソースごとにやり方が異なるよりは、もう完全に分けてしまったほうが混乱しないという判断。
参考
やってみた
$ sam init
質問はこんな感じで。
Which template source would you like to use?
1 - AWS Quick Start Templates
2 - Custom Template Location
Choice: 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 - Hello World Example With Powertools
8 - Infrastructure event management
9 - Serverless Connector Hello World Example
10 - Multi-step workflow with Connectors
11 - Lambda Response Streaming
12 - Lambda EFS example
13 - DynamoDB Example
14 - Machine Learning
Template: 1
Use the most popular runtime and package type? (Python and zip) [y/N]: 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 - java17
10 - java11
11 - java8.al2
12 - java8
13 - nodejs18.x
14 - nodejs16.x
15 - nodejs14.x
16 - nodejs12.x
17 - python3.9
18 - python3.8
19 - python3.7
20 - python3.10
21 - ruby2.7
22 - rust (provided.al2)
Runtime: 20
What package type would you like to use?
1 - Zip
2 - Image
Package type: 2
Based on your selections, the only dependency manager available is pip.
We will proceed copying the template using pip.
Would you like to enable X-Ray tracing on the function(s) in your application? [y/N]: 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]: N
Project name [sam-app]:
$ cd sam-app
次にSAMテンプレートを修正する
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
python3.10
Sample SAM Template for sam-app
Globals:
Function:
Timeout: 3
Parameters:
ENV:
Type: String
AllowedValues:
- dev
- prod
Default: dev
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub hello-world-${ENV}
PackageType: Image
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api
Properties:
Path: /hello
Method: get
FunctionUrlConfig:
AuthType: NONE
Metadata:
Dockerfile: Dockerfile
DockerContext: ./hello_world
DockerTag: !Ref ENV
Outputs:
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
HelloWorldFunctionUrl:
Description: "Hello World Lambda Function URL Endpoint"
Value:
Fn::GetAtt: HelloWorldFunctionUrl.FunctionUrl
以下で外部からのパラメータを受けるようにする。デフォルトは"dev"にしている。
Parameters:
ENV:
Type: String
AllowedValues:
- dev
- prod
Default: dev
Lambdaの関数名に環境を付与するようにする。
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub hello-world-${ENV}
今回はコンテナイメージを使うので、タグにも付与しておく。実際にはバージョン情報とかリリースとかコミットIDとかを付与したほうがいいのかなーと思うけど、とりま。
(snip)
HelloWorldFunction:
(snip)
Metadata:
Dockerfile: Dockerfile
DockerContext: ./hello_world
DockerTag: !Ref ENV
(snip)
あと今回はAPI GatewayではなくLambda FunctionURLsを使うことにする。Lambdaのプロパティに以下を追加。今回はAuthTy
(snip)
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
(snip)
FunctionUrlConfig:
AuthType: NONE
(snip)
Outputsもそれに合わせて以下を追加。元々あったAPI Gatewayのエントリは削除した。
Outputs:
(snip)
HelloWorldFunctionUrl:
Description: "Hello World Lambda Function URL Endpoint"
Value:
Fn::GetAtt: HelloWorldFunctionUrl.FunctionUrl
パッケージ作成。
$ sam build
$ sam deploy --guided
質問はこんな感じ。デフォルトは"dev"としている。IAMとかLambdaの認証とか、色々詰めないといけないことはあるけど、とりま。
Stack Name [sam-app]: sam-app-dev
AWS Region [ap-northeast-1]:
Parameter ENV [dev]:
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [Y/n]: 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]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
HelloWorldFunction Function Url may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]:
完了したらこんな感じ。
CloudFormation outputs from deployed stack
--------------------------------------------------------------------------------------------------------------------------------------------
Outputs
--------------------------------------------------------------------------------------------------------------------------------------------
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value arn:aws:iam::XXXXXXXXXXXX:role/sam-app-dev-HelloWorldFunctionRole-xxxxxxxxxxxx
Key HelloWorldFunctionUrl
Description Hello World Lambda Function URL Endpoint
Value https://xxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:hello-world-dev
--------------------------------------------------------------------------------------------------------------------------------------------
Successfully created/updated stack - sam-dev in ap-northeast-1
FunctionURLにアクセスしてちゃんと応答が返ってきている。
$ curl https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
{"message": "hello world"}
では次に"Prod"の設定をしつつデプロイ
$ sam deploy --guided
スタック名やENV、SAMの設定上の環境を"prod"向けに書き換えている。
Stack Name [sam-app-dev]: sam-app-prod
AWS Region [ap-northeast-1]:
Parameter ENV [dev]: prod
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [Y/n]: 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]: Y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: N
HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: y
HelloWorldFunction Function Url may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: Y
SAM configuration file [samconfig.toml]:
SAM configuration environment [default]: prod
作成されたものはこれ。
Outputs
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value arn:aws:iam::XXXXXXXXXXXX:role/sam-app-prod-HelloWorldFunctionRole-xxxxxxxxxxxx
Key HelloWorldFunctionUrl
Description Hello World Lambda Function URL Endpoint
Value https://xxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:hello-world-prod
---------------------------------------------------------------------------------------------------------------------------------------------------------------
なるほど。スタックを分けた場合にはスタック名がリソースに付与されるっぽい。Lambdaの関数名に環境を渡して命名してるけど、これって必要なんだろうか???
とりあえずできたリソースを見てみる。
$ aws cloudformation list-stacks | jq -r '.StackSummaries[] | select( .StackStatus != "DELETE_COMPLETE" ) | .StackName' | grep -i sam-app
sam-app-prod
sam-app-prod-93e0fccc-CompanionStack
sam-app-dev
sam-app-dev-341f0582-CompanionStack
$ aws lambda list-functions | jq -r '.Functions[] | .FunctionName' | grep "hello-world"
hello-world-prod
hello-world-dev
$ aws iam list-roles | jq -r '.Roles[] | .RoleName' | grep sam-app
sam-app-dev-HelloWorldFunctionRole-1LS1ITHGEYB1D
sam-app-prod-HelloWorldFunctionRole-7JLLWED3RK7O
ちゃんスタック分かれてるし、リソース名からどっちの環境なのか判断できる。でもこれならLambdaにもスタック名をプリフィクスとしてつけてほしい。FunctionNameでわざわざ環境変数付与したけどやっぱり不要かも。外してやってみる。
さっきは--guided使ったけどsamconfig.tomlの設定ができたら、以降はdeployで--config-env
で環境指定すれば良い。指定しない場合はdefault(今回の設定だとdev)が読み込まれる。
$ sam build
$ sam deploy
結果
Outputs
---------------------------------------------------------------------------------------------------------------------------------------------------------------
Key HelloWorldFunctionIamRole
Description Implicit IAM Role created for Hello World function
Value arn:aws:iam::XXXXXXXXXXXX:role/sam-app-dev-HelloWorldFunctionRole-xxxxxxxxxxxx
Key HelloWorldFunctionUrl
Description Hello World Lambda Function URL Endpoint
Value https://xxxxxxxxxxxx.lambda-url.ap-northeast-1.on.aws/
Key HelloWorldFunction
Description Hello World Lambda Function ARN
Value arn:aws:lambda:ap-northeast-1:XXXXXXXXXXXX:function:sam-app-dev-HelloWorldFunction-GRIkzKsOYDcA
---------------------------------------------------------------------------------------------------------------------------------------------------------------
こっちでいいんじゃないかという気がする。ちゃんとスタック名でわかるし。template.yaml内での名称(HelloWorldFunction)が付与される感じっぽい。
ということでGitHub Actionsでデプロイまでやっちゃう。