🔖

Terraform だけで ECS タスクを業務時間外は停止させる!

2022/12/04に公開

この記事はスターフェスティバル Advent Calendar 2022 4 日目の記事です

https://qiita.com/advent-calendar/2022/stafes

昨日は @koonagi食事付きのオンライン採用イベントを開催しました! でした
どんなメンバーが働いているのか、どんな課題に取り組んでいるのかをランチを食べながら気軽に知れるイベントとなっておりますので、ぜひ応募してみてください!


はじめに

2022 年は円安の影響もあり AWS のコストが今まで以上に上がってしまいましたね
その影響もあり、僕が所属しているスターフェスティバルでは AWS のコスト削減の機運が高まることになりました
インフラよくわからん勢の僕ですが、少しでもコスト削減に協力したい!ということで僕が担当しているアプリケーション(Fargate)を業務時間外は自動で停止させるということをやってみることにしました!

しかし、いざ調べてみると Lambda を作らないといけないなど少し手間がかかるやり方が多く、もう少し楽にやりたい!となってしまったのでこの記事ではその方法を紹介します!

やり方

AWS には ECS タスクのスケーリングを任意の時間に実行する仕組みがあります

https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/ec2-auto-scaling-scheduled-scaling.html

この仕組みを使って業務の終了時間に ECS タスクを 0 個にスケールインし業務の開始時間に n 個にスケールアウトすれば Lambda などを作らずに済むのではと考えました

この方法では、terraform 上で新たに aws_appautoscaling_targetaws_appautoscaling_scheduled_action を扱うだけで済みます
そのため、Lambda などを作成せずに terraform をちょっといじるだけで完結することができ、とても楽です!

aws_appautoscaling_target

正直あまりわかってないですが オートスケーリングの対象となるリソースの定義です

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target

aws_appautoscaling_scheduled_action

このリソースでは何時にどんなスケーリングをするかといった定義を行えます

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_scheduled_action

今回のユースケースでは

  • 業務終了時間にタスク数を 0 にし
  • 業務開始時間にタスク数を元に戻す

という 2 つの aws_appautoscaling_scheduled_action を作成すれば良いことになります

コード例

それでは実際に書いたコードを若干改変して紹介します

locals {
  # for_eachで回せるようにすることで、停止させるサービスの増減に手軽に対応できるように
  ecs_services = {
    # 同じサービスが重複して存在しないよう、サービス名をキーにしている
    # (クラスタを跨げば同じサービス名が存在することはありえるが、弊社のサービスの命名規則的にありえないためこんな感じに)
    "${aws_ecs_service.foo-service.name}" = {
      cluster      = aws_ecs_cluster.foo-cluster.name
      max_capacity = 2
      min_capacity = 1
    }
    # ...
  }
}

# サービスごとの aws_appautoscaling_target を作成
resource "aws_appautoscaling_target" "down-ecs-appautoscaling-target" {
  for_each = local.ecs_services

  max_capacity       = each.value.max_capacity
  min_capacity       = each.value.min_capacity
  resource_id        = "service/${each.value.cluster}/${each.key}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

# サービスごとに22時になったらタスク数を0にするスケジュールを組む
# 弊社はコアタイムなしのフルフレックスなので22時まで働いていいのだ。朝が弱い人でも安心!
resource "aws_appautoscaling_scheduled_action" "down-ecs-task-scheduled-action" {
  for_each = local.ecs_services

  name               = "${each.key}-down"
  service_namespace  = aws_appautoscaling_target.down-ecs-appautoscaling-target[each.key].service_namespace
  resource_id        = aws_appautoscaling_target.down-ecs-appautoscaling-target[each.key].resource_id
  scalable_dimension = aws_appautoscaling_target.down-ecs-appautoscaling-target[each.key].scalable_dimension
  schedule           = "cron(0 22 ? * * *)"
  timezone           = "Asia/Tokyo"

  scalable_target_action {
    min_capacity = 0
    max_capacity = 0
  }
}

# サービスごとに朝5時になったらタスク数を元に戻すスケジュールを組む
# 早く出社して昼過ぎに退勤すると1日がめちゃ長く感じるのでオススメ!
resource "aws_appautoscaling_scheduled_action" "up-ecs-task-scheduled-action" {
  for_each = local.ecs_services

  name               = "${each.key}-up"
  service_namespace  = aws_appautoscaling_target.down-ecs-appautoscaling-target[each.key].service_namespace
  resource_id        = aws_appautoscaling_target.down-ecs-appautoscaling-target[each.key].resource_id
  scalable_dimension = aws_appautoscaling_target.down-ecs-appautoscaling-target[each.key].scalable_dimension
  schedule           = "cron(0 5 ? * * *)"
  timezone           = "Asia/Tokyo"

  scalable_target_action {
    max_capacity = each.value.max_capacity
    min_capacity = each.value.min_capacity
  }
}

おわりに

この記事では Terraform だけで ECS タスクを増減させる方法を紹介しました
冒頭でも軽く触れましたが、僕自身は AWS にそこまで詳しくないため、もっと良い方法がある場合は是非教えてください!

また最近新たに弊社のプロダクト開発部の Twitter アカウントができたので、フォローしてみてください!
https://twitter.com/stafes_tech

明日は DPontaro による Prisma に関する記事です!お楽しみに!

スタフェステックブログ

Discussion