はじめに
AWS Lambda + SpringNativeでWebAPIを構築したときに、
SpringNativeといえどもコールドスタートが発生するため、
provisioned concurrencyを設定していました。
ただしprovisioned concurrencyを固定値にしていたので、
auto scalingに変更しました。
TL;DL
比較的簡単にできました。
ソースはここに置いてあります。
やったこと
Lambda関数の作成
Lambda関数を作成します。
関数は複数個作ることを想定しているため、
関数のパラメーターをリスト化しています。
パラメーターの中に予約実行を設定するかのフラグを持たせています。
また予約実行をする場合にスケジュールされたオートスケール
かターゲット追跡のオートスケール
かを設定するようにしています。
これらのパラメーターを使い、lambdaのリソースを作るときにfor_eachで関数を作成するようにしています。
あと検証用なのでLambda関数URLを使っています。
lambda.tf
###################################################################################
# Lambda関数関連リソース
###################################################################################
locals {
provisioned_type_tracking = "tracking"
provisioned_type_scheduled = "scheduled"
# 関数リスト
function_list = [
{ function_name = "function-1", memory_size = 128, timeout = 3, provisioned = { enable = true, target_alias = "dev", type = local.provisioned_type_tracking, min_capacity = 1, max_capacity = 2 } },
{ function_name = "function-2", memory_size = 128, timeout = 3, provisioned = { enable = true, target_alias = "dev", type = local.provisioned_type_scheduled, min_capacity = 0, max_capacity = 1 } },
]
# エイリアス名
alias_name = "dev"
}
# Lambda関数本体
resource "aws_lambda_function" "main" {
for_each = { for i in local.function_list : i.function_name => i }
# Lambda関数ごとの設定
function_name = each.value.function_name
timeout = each.value.timeout
memory_size = each.value.memory_size
# 全lambda関数の共通設定
filename = data.archive_file.main.output_path
role = aws_iam_role.lambda.arn
runtime = "nodejs16.x"
handler = "index.handler"
publish = true
}
# Lambda関数URL
resource "aws_lambda_function_url" "main" {
for_each = aws_lambda_function.main
function_name = each.value.function_name
qualifier = local.alias_name
authorization_type = "NONE"
}
# Lambdaエイリアス
resource "aws_lambda_alias" "main" {
for_each = aws_lambda_function.main
function_name = each.value.arn
function_version = each.value.version
name = local.alias_name
description = "開発用エイリアス"
}
スケジュールされたオートスケールの作成
関数のパラメーターリストからスケジュールされたオートスケールを設定する関数のみを抽出して、オートスケールを作成しています。
lambda.tf
###################################################################################
# Lambda関連オートスケールソース(スケジュール)
###################################################################################
# スケジュールされたオートスケール用のターゲットを作成
resource "aws_appautoscaling_target" "scheduled" {
depends_on = [aws_lambda_function.main]
for_each = { for i in local.function_list : i.function_name => i if can(tobool(i.provisioned.enable)) && strcontains(i.provisioned.type, local.provisioned_type_scheduled) }
resource_id = "function:${each.value.function_name}:${local.alias_name}"
min_capacity = each.value.provisioned.min_capacity
max_capacity = each.value.provisioned.max_capacity
scalable_dimension = "lambda:function:ProvisionedConcurrency"
service_namespace = "lambda"
}
# スケジュールされたスケールイン
resource "aws_appautoscaling_scheduled_action" "scheduled_in" {
for_each = aws_appautoscaling_target.scheduled
service_namespace = each.value.service_namespace
resource_id = each.value.resource_id
scalable_dimension = each.value.scalable_dimension
name = "scheduled_in"
schedule = "cron(40 21 ? * * *)"
timezone = "Asia/Tokyo"
scalable_target_action {
min_capacity = each.value.min_capacity
max_capacity = each.value.min_capacity
}
}
# スケジュールされたスケールアウト
resource "aws_appautoscaling_scheduled_action" "scheduled_out" {
for_each = aws_appautoscaling_target.scheduled
service_namespace = each.value.service_namespace
resource_id = each.value.resource_id
scalable_dimension = each.value.scalable_dimension
name = "scheduled_out"
schedule = "cron(20 21 ? * * *)"
timezone = "Asia/Tokyo"
scalable_target_action {
min_capacity = each.value.max_capacity
max_capacity = each.value.max_capacity
}
}
ターゲット追跡のオートスケールの作成
こちらもパラメーターからターゲット追跡の対象となる関数のみを抽出して設定しています。
lambda.tf
###################################################################################
# Lambda関連オートスケールソース(ターゲット追跡型)
###################################################################################
# ターゲット追跡型のオートスケール用のターゲットを作成
resource "aws_appautoscaling_target" "tracking" {
depends_on = [aws_lambda_function.main]
for_each = { for i in local.function_list : i.function_name => i if can(tobool(i.provisioned.enable)) && strcontains(i.provisioned.type, local.provisioned_type_tracking) }
resource_id = "function:${each.value.function_name}:${local.alias_name}"
min_capacity = each.value.provisioned.min_capacity
max_capacity = each.value.provisioned.max_capacity
scalable_dimension = "lambda:function:ProvisionedConcurrency"
service_namespace = "lambda"
}
# ターゲット追跡(70%)
resource "aws_appautoscaling_policy" "tracking_policy" {
for_each = aws_appautoscaling_target.tracking
resource_id = each.value.resource_id
service_namespace = each.value.service_namespace
scalable_dimension = each.value.scalable_dimension
name = "tracking"
policy_type = "TargetTrackingScaling"
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "LambdaProvisionedConcurrencyUtilization"
}
target_value = 0.7
}
}