LoginSignup
0
1
100万人に伝えたい!失敗を乗り超えた話を共有しよう

TerraformでAWS Lambdaのauto scaling(provisioned concurrency)を設定してみた

Posted at

はじめに

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
  }
}
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1