初めに
本日リリースされたAWS SAM CLIのv1.90.0
にてsam local start-api
がTerraformをサポートするようになりました。
以前からアップデートに本機能関連のアップデートが含まれていたのでついに来たかという感じです。
本機能限らずですがSAMでTerraformを利用可能な機能については厳密にはネイティブにサポートしているわけではなく、内々的にはterraformコマンドの結果を元にCloudFormationテンプレートに変換しているものとなります。
具体的な仕組みは過去のマージコミットからかいつまんで見ている程度となりますが、コア部分はおそらく以下の部分となりますので興味のある人は読んで見てはいかがでしょうか。
実行バージョン
前述した通り内部的にはterraformコマンドを利用していますのでsamとは別にterraformコマンドが必要となります。
% sam --version
SAM CLI, version 1.90.0
# しばらくterraform使っていなかった関係でバージョンが低いです
% terraform --version
Terraform v1.3.2
on darwin_arm64
コード
main.tf
以外はsam init
でデフォルトで生成されているhello_worldのコードを利用しています。
main.tf
provider "aws" {
profile = "default"
region = "ap-northeast-1"
}
resource "aws_api_gateway_rest_api" "sam_api" {
name = "sam-api"
description = "sam local testing"
}
resource "aws_api_gateway_resource" "hello_world" {
rest_api_id = aws_api_gateway_rest_api.sam_api.id
parent_id = aws_api_gateway_rest_api.sam_api.root_resource_id
path_part = "hello"
}
resource "aws_api_gateway_method" "hello_world" {
rest_api_id = aws_api_gateway_rest_api.sam_api.id
resource_id = aws_api_gateway_resource.hello_world.id
http_method = "GET"
authorization = "NONE"
}
resource "aws_api_gateway_integration" "hello_world" {
rest_api_id = aws_api_gateway_rest_api.sam_api.id
resource_id = aws_api_gateway_resource.hello_world.id
http_method = aws_api_gateway_method.hello_world.http_method
uri = aws_lambda_function.hello_world.invoke_arn
type = "AWS_PROXY"
}
resource "aws_lambda_function" "hello_world" {
filename = "hello_world/"
function_name = "HelloWorldFunction"
handler = "app.lambda_handler"
runtime = "python3.9"
role = aws_iam_role.lambda_role.arn
memory_size = 128
timeout = 60
architectures = ["arm64"]
}
resource "aws_iam_role" "lambda_role" {
name = "LambdaRole"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "lambda.amazonaws.com"
}
}
]
})
}
※ 2023/09/04追記
別件で検証してたところbuild後のアーティファクトにpythonコードのビルド結果がないと思ったらsam metadata resourceが必要らしいです。
今回のコードの場合はpythonコードがビルドが不要(requirements.txtにインストールが必要なものがない)だったので通ってました。
実行
現在terraformが対応している他のコマンド同様に、実行時に--hook-name
オプションにterraform
を指定することで実行が可能です。
なお現時点ではSAM上でのterraform利用自体がベータ機能となっているため非対話式に実行したい場合は--beta-features
オプションの指定が必要です。
--beta-features
は指定がなくとも実行は可能ですが、実行のたびに確認が発生します。
% sam local start-api --hook-name terraform
Supporting Terraform applications is a beta feature.
Please confirm if you would like to proceed using AWS SAM CLI with terraform application.
You can also enable this beta feature with 'sam local invoke --beta-features'. [y/N]: y
Experimental features are enabled for this session.
Visit the docs page to learn more about the AWS Beta terms https://aws.amazon.com/service-terms/.
改めて実行してみます。
% sam local start-api --hook-name terraform --beta-features
...
Finished generating metadata file. Storing in /xxx/sam-app-terraform/.aws-sam-iacs/iacs_metadata/template.json
Prepare hook completed and metadata file generated at: /xxx/sam-app-terraform/.aws-sam-iacs/iacs_metadata/template.json
Initializing the lambda functions containers.
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.9-rapid-arm64.
Mounting /xxx/sam-app-terraform/hello_world as /var/task:ro,delegated, inside runtime container
Containers Initialization is done.
Mounting HelloWorldFunction 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
2023-07-07 17:42:27 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
2023-07-07 17:42:27 Press CTRL+C to quit
# 別の画面でcurlを実行
# % curl http://127.0.0.1:3000/hello
# {"message": "hello world"}%
Invoking app.lambda_handler (python3.9)
Reuse the created warm container for Lambda function 'aws_lambda_function.hello_world'
Lambda function 'aws_lambda_function.hello_world' is already running
END RequestId: 760b8b37-7fef-4ad8-95c6-fa8ad2ac07ba
REPORT RequestId: 760b8b37-7fef-4ad8-95c6-fa8ad2ac07ba Init Duration: 0.26 ms Duration: 108.17 ms Billed Duration: 109 ms Memory Size: 128 MB Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2023-07-07 17:45:33 127.0.0.1 - - [07/Jul/2023 17:45:33] "GET /hello HTTP/1.1" 200 -
terraformのモジュールを利用してsam local start-api
が利用できることが確認できました。
実は以前のバージョンからある程度対応していた
先に書かせていただいた通り、本件に関する機能追加は行われており変換処理等の実装は進められていましたが、
sam local start-api
コマンドに--hook-name
オプションが存在しないため、実際直接の実行ができないものとなっておりました。
今回検証中に変更した内容が反映されずsam build
を試したところビルドの成果物として変換後のCloudFormationテンプレートが生成されている為、
もしやと思い確認したところ、あくまでstart-api
での直接の呼び出しが対応していないだけでbuild
を経由することで以前のバージョンでも利用可能でした。
やり方としてはsam build
時に--hook-name terraform
を指定し、sam loval start-api
を実行するだけです。
## キャッシュ等が影響しないように事前に.aws-sam(-iacs)フォルダを消しておく
% rm -rf .aws-sam*
## venvで環境を作成しpipで古いバージョンsamを準備しておく
## NOTE: brewは現在最新版しか保持していない
% /tmp/sam189/bin/sam --version
SAM CLI, version 1.89.0
## sam buildを実行する
% /tmp/sam189/bin/sam build --hook-name terraform --beta-features
...
Build Succeeded
Built Artifacts : .aws-sam/build
Built Template : .aws-sam/build/template.yaml
Commands you can use next
=========================
[*] Invoke Function: sam local invoke --hook-name terraform
[*] Emulate local Lambda functions: sam local start-lambda --hook-name terraform
ビルドの成果物として.aws-sam/build/template.yaml
に変換後のCloudFormationテンプレートが存在します。
AWSTemplateFormatVersion: '2010-09-09'
Resources:
AwsApiGatewayMethodHelloWorld0E3B471C:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: GET
AuthorizationType: NONE
RestApiId:
Ref: AwsApiGatewayRestApiSamApiB178E174
ResourceId:
Ref: AwsApiGatewayResourceHelloWorld3E1F8155
Integration:
Uri:
Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AwsLambdaFunctionHelloWorld4ED843CE.Arn}/invocations
Type: AWS_PROXY
ConnectionType: INTERNET
Metadata:
SamResourceId: aws_api_gateway_method.hello_world
AwsApiGatewayResourceHelloWorld3E1F8155:
Type: AWS::ApiGateway::Resource
Properties:
PathPart: hello
RestApiId:
Ref: AwsApiGatewayRestApiSamApiB178E174
ParentId:
Fn::GetAtt:
- AwsApiGatewayRestApiSamApiB178E174
- RootResourceId
Metadata:
SamResourceId: aws_api_gateway_resource.hello_world
AwsApiGatewayRestApiSamApiB178E174:
Type: AWS::ApiGateway::RestApi
Properties:
Name: sam-api
Metadata:
SamResourceId: aws_api_gateway_rest_api.sam_api
AwsLambdaFunctionHelloWorld4ED843CE:
Type: AWS::Lambda::Function
Properties:
FunctionName: HelloWorldFunction
Architectures:
- arm64
Code: /xxxx/sam-app-terraform/hello_world
Handler: app.lambda_handler
PackageType: Zip
Runtime: python3.9
Timeout: 60
MemorySize: 128
Metadata:
SamResourceId: aws_lambda_function.hello_world
SkipBuild: true
Metadata:
AWS::SAM::Hook:
HookName: terraform
この時点ですでにCloudFormationテンプレートができているのでsam local start-api
実行時には--hook-name
オプション等は不要です。
% /tmp/sam189/bin/sam local start-api
Initializing the lambda functions containers.
Local image is up-to-date
Using local image: public.ecr.aws/lambda/python:3.9-rapid-arm64.
Mounting /xxx/git/sam-app-terraform/hello_world as /var/task:ro,delegated, inside runtime container
Containers Initialization is done.
Mounting HelloWorldFunction at http://127.0.0.1:3000/hello [GET]
...
* Running on http://127.0.0.1:3000
2023-07-07 18:11:45 Press CTRL+C to quit
Invoking app.lambda_handler (python3.9)
Reuse the created warm container for Lambda function 'aws_lambda_function.hello_world'
Lambda function 'aws_lambda_function.hello_world' is already running
START RequestId: 9242f13c-2f7d-48d7-9016-edf50a10ba53 Version: $LATEST
END RequestId: 9242f13c-2f7d-48d7-9016-edf50a10ba53
REPORT RequestId: 9242f13c-2f7d-48d7-9016-edf50a10ba53 Init Duration: 0.78 ms Duration: 120.52 ms Billed Duration: 121 ms Memory Size: 128 MB Max Memory Used: 128 MB
No Content-Type given. Defaulting to 'application/json'.
2023-07-07 18:12:51 127.0.0.1 - - [07/Jul/2023 18:12:51] "GET /hello HTTP/1.1" 200 -
どこが境界かなと思いましたが少なくとも今回の実装内容であれば1.85.0
から対応していたようです。
v1.82.0
は変換が不十分で実行はできるがメソッド等が結びついていない(apigw関連の初回追加バージョン)v1.84.0
も変換が不十分でアクセスするとInternal server error
となるv1.85.0
今回実装の内容では正常に実行可能
あくまで今回のサンプルの実装で実行をした場合となり1.90.0
に比べ機能が不足している可能性がある点はご注意ください。
終わりに
今回のアップデートで実質的にsam local
全般がterraformに対応しました。
厳密にはgenerate-event
は未対応ですがイベントを生成するだけでテンプレートが何であるかは関係ないので対応自体はないものと思っています。
デプロイに関してはそもそもterraformの機能でありますし、ローカルの開発サポートが完了したので安定確認できたあたりでベータが外れるのか、デプロイ諸々対応するまで外れないのかは少し気になるところです。