OpenWork Tech Blog

社員クチコミサービスを運営しているオープンワークエンジニアによるテックブログです。

ECS AutoScalingとEventBridge Schedulerを利用したスケーリング定期自動化

はじめに

オープンワークでは2023年7月スタートのカンテレ・フジテレビ系月10ドラマ「転職の魔王様」(成田凌さんが主演、小芝風花さんヒロイン役)とコラボし、ドラマ枠内でインフォマーシャルを放映しておりました。(詳細はこちらのリンクをご参照ください。)

www.youtube.com

放映に伴うアクセス増加を見積もった結果、WebサーバーとWebサーバーから利用している一部のリソースの増強が必要という事がわかりました。 ドラマの放映期間は2か月超に及ぶので、放映時間外もリソースを増強したままにするのはコストが高くなりすぎてしまいます。放映日に合わせて週次で手作業でスケーリングする方法もありますが、運用コストが掛かり、かつ、作業ミス等の懸念もあります。 今回はスケジュールベースでのオートスケールを利用することでこれらの課題に対処しました。

OpenWorkのサービス構成

OpenWorkのサービス構成はいわゆる一般的なWebサービスの構成となっております。WebサーバーはECS on Fargateを利用してコンテナで動作しており、バックエンドのリソース等に各種マネージドサービスを利用しています。

OpenWorkの構成概要

コンテナ化の経緯や構成の特徴などに興味がある場合は下記記事をご覧ください。 techblog.openwork.co.jp

Webサーバーのスケールアウト/イン

WebサーバーはECS on Fargateで稼働しているので、Application AutoScalingを利用してスケジュールベースのスケーリングを設定しました。 通常時はサーバー負荷に応じたStep Scalingのみですが、これに追加して放映タイミングに合わせたコンテナ台数増減をしています。

resource "aws_appautoscaling_target" "this" {
  max_capacity       = var.max_capacity
  min_capacity       = var.min_capacity
  role_arn           = data.aws_iam_role.ecs_service_autoscaling.arn
  resource_id        = "service/${var.cluster_name}/${var.service_name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_scheduled_action" "this" {
  name               = 
  service_namespace  = aws_appautoscaling_target.this.service_namespace
  resource_id        = aws_appautoscaling_target.this.resource_id
  scalable_dimension = aws_appautoscaling_target.this.scalable_dimension
  timezone           = var.timezone
  schedule           = "cron(30 21 ? * MON *)"

  scalable_target_action {
    min_capacity = var.min_capacity
    max_capacity = var.max_capacity
  }
  depends_on = [aws_appautoscaling_target.this]

スケーリングの通知にはEventBridgeを利用しています。下記のイベントをSNS経由でLambdaに送り、少し加工処理をしてSlack通知しています。

resource "aws_cloudwatch_event_rule" "this" {
  name          = "autoscaling-scaling-activity"
  event_pattern = jsonencode(
    {
      source = [
        "aws.application-autoscaling"
      ]
      detail-type = [
        "Application Auto Scaling Scaling Activity State Change"
      ]
      detail = {
        resourceId = var.resource_ids
      }
    }
  )
}

AutoScalingの通知

バックエンドリソースのスケールアップ/ダウン

スケール対象のバックエンドリソースはスケジュールでスケーリングする機能がありませんでした。 EventBridgeとLambdaの組み合わせや、運用しているサーバー上でAWS CLIをcron実行するなどの候補もありましたが、今回はEventBridge Schedulerを利用しました。

EventBridge Schedulerは、270を超える AWSサービスと6,000を超えるAPI オペレーションを呼び出すことができるため、設定次第でほとんどの操作は実行可能となっており、今回の対象サービスの操作も実行する事ができました。 docs.aws.amazon.com

resource "aws_scheduler_schedule" "this" {
  for_each = var.parameters

  name       = "${var.name}-${replace(each.key, "_", "-")}"
  group_name = aws_scheduler_schedule_group.this.name

  start_date = try(timeadd(each.value.start_date, "-9h"), null)
  end_date   = try(timeadd(each.value.end_date, "-9h"), null)

  schedule_expression          = each.value.schedule_expression
  schedule_expression_timezone = "Asia/Tokyo"

  flexible_time_window {
    mode = "OFF"
  }


  target {
    arn      = each.value.target.arn
    role_arn = aws_iam_role.this[each.key].arn
    input    = jsonencode(each.value.target.input)

    retry_policy {
      maximum_event_age_in_seconds = can(each.value.target.retry_policy["maximum_event_age_in_seconds"]) ? each.value.target.retry_policy.maximum_event_age_in_seconds : null
      maximum_retry_attempts       = can(each.value.target.retry_policy["maximum_retry_attempts"]) ? each.value.target.retry_policy.maximum_retry_attempts : null
    }
  }
}

通知には下記イベントルールを利用してEventBridgeSchedulerによるAPIコールを検知してAutoScalingと同様にSlack通知しています。

resource "aws_cloudwatch_event_rule" "this" {
  name          = "eventbridge-scheduler-activity"
  description   = "Notice when eventbridge scheduler activity."
  event_pattern = jsonencode(
    {
      detail = {
        userAgent = [{"prefix": "AmazonEventBridgeScheduler,"}]
        userIdentity = {
          arn = [{"prefix": "arn:aws:sts::xxxxxxxx:assumed-role/${var.prefix}-"}]
        }
      }
    }
  )
}

EventBridge Schedulerの通知

まとめ

CM放映時は急激なアクセス増加がありましたが、必要なスケーリングを適切なタイミングで実施する事で大きな問題を発生せずに捌き切る事ができました。

リクエスト件数推移(req/seq)

スケジュールベースのオートスケールを利用することで、手作業による運用と比較すると1/5程度の利用料金で済み、なおかつ、作業が不要となったため他の業務に時間を有効活用することができました。 思惑通りに動作するかという心配もありましたが、通知を実装しておくことで安心して見守る事ができています。

スケジュールベースのスケールは今回の様なイベント時は特に有効ですが、日常のpeak/offpeakにあわせたリソース調整に利用してもよいかもしれません。 また、EventBridge SchedulerはAWSの多くのAPIの実行が可能となっており、本番/開発を問わず様々な場面での活用が考えられそうです。今後の有効活用を検討していきたいと思います。

最後に

オープンワークのインフラチームではサービス改善、運用改善のためにできる事を日々模索しています。 新しい技術、サービスを取り入れてシステムを改善していく事に興味がある方は、ぜひ弊社の求人を覗いてみてください。 www.openwork.co.jp