💈

[Terraform]ECS Fargateのオートスケーリング設定

2022/12/06に公開

スペースマーケットでSREを担当しています小見です。
今回は、ECSFargate環境でオートスケーリング設定調査を行った時の記事となります。
主に以下記事を強く参考にしております。
https://blog.adachin.me/archives/47303

オートスケーリングとは?

今回実現したいオートスケーリングは、ECSFargate環境下で、CPU使用率を軸にしたオートスケーリングの設定となります。

ECSのCPUメトリクスを監視して、必要に応じてECSタスク数を増やしたり減らしたり自動的に制御してくれる設定となります。

概要

ECSでオートスケーリングを行うためには、以下terraformリソースの記述が必要になります。

  • aws_appautoscaling_target
    • オートスケーリング基本設定のリソースになります。
    • 今回は、オートスケールの上限下限の設定を行います。
  • aws_appautoscaling_policy
    • スケール挙動設定のリソースになります。
    • 今回は、タスクの追加とタスクの削除の設定を行います。
  • aws_cloudwatch_metric_alarm
    • スケール発火トリガーのリソースになります。
    • 今回は、CPU使用率を監視して、予定したCPU使用率(閾値)に達したときにアラートを挙げます。

イメージとしましては、
aws_cloudwatch_metric_alarmがCPU使用率を監視して、閾値に達したときに
aws_appautoscaling_policyの動作をさせることになります。

リソース詳細

ここからはそれぞれどのように設定を行えばオートスケーリングが行えるか記述していきます。
細かい設定内容に関してはコメントに記載しておりますので、そちらもご覧いただければと思います。

aws_appautoscaling_target

resource "aws_appautoscaling_target" "appautoscaling_ecs_target" {
  service_namespace  = "ecs"
  
  # 紐付けたいECSのサービスを設定します。
  # 注意点としては、ARN等ではなく、以下の様にクラスター名/サービス名での紐付けになります。
  resource_id        = "service/${var.ecs_cluster_name}/${var.ecs_service_name}"
  scalable_dimension = "ecs:service:DesiredCount"

   # オートスケーリングを実行するRoleArnを設定してください。
   # 今回はAWS側で管理されているRole(AWSServiceRoleForApplicationAutoScaling_ECSService)を利用しています。
  role_arn           = data.aws_iam_role.ecs_service_autoscaling.arn

  # オートスケーリングさせる時の最低値と最大値です。
  # サーバー台数が無限に増え続けないように事前に上限の設定を行います。
  min_capacity       = var.min_capacity
  max_capacity       = var.max_capacity
}

# Roleの読み込みです。
data "aws_iam_role" "ecs_service_autoscaling" {
  name = "AWSServiceRoleForApplicationAutoScaling_ECSService"
}

aws_appautoscaling_policy

aws_appautoscaling_policyは、増加、減少の両方の設定を行うため、それぞれ一つずつの設定が必要になります。

# サーバ台数増加設定
resource "aws_appautoscaling_policy" "appautoscaling_scale_up" {
  # policyのnameです。
  # workspaceを利用している場合は、workspaceを利用している場合、workspaceをnameに入れ込み環境ごとに区別できることをお勧めします。
  name               = "service_name_scale_up_${terraform.workspace}"
  service_namespace  = "ecs"
  
  # 紐付けたいECSのサービスを設定します。
  # 注意点としては、ARN等ではなく、以下の様にクラスター名/サービス名での紐付けになります。
  resource_id        = "service/${var.ecs_cluster_name}/${var.ecs_service_name}"
  scalable_dimension = "ecs:service:DesiredCount"

  step_scaling_policy_configuration {
    # サーバ台数を増減させ方の種類です。詳しくは以下ドキュメントを参照してください。
    # https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/as-scaling-simple-step.html#as-scaling-adjustment
    adjustment_type         = "ChangeInCapacity"
    
    # クールダウンタイム
    # スケーリング判断を連続で発生させてしまうと、一気に上限値まで上がったり、下限値まで下がったりすることを防ぐためのものだと思われます。
    # 詳しくは以下を参照してください。
    # https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/ec2-auto-scaling-scaling-cooldowns.html
    cooldown                = 120
    metric_aggregation_type = "Average"

    step_adjustment {
      metric_interval_lower_bound = 0
      # 一度に増加させたいサーバ台数を設定します。
      scaling_adjustment          = 1
    }
  }
}

# サーバ台数減少設定
resource "aws_appautoscaling_policy" "appautoscaling_scale_down" {
    ...
    # aws_appautoscaling_policy.appautoscaling_scale_upと基本的には同じため省略
    ...
    step_adjustment {
      metric_interval_lower_bound = 0
      # 一度に減少させたいサーバ台数を設定します。
      # 負の数を設定することでサーバ台数を減らすことができます。
      scaling_adjustment          = -1
    }
  }
}

aws_cloudwatch_metric_alarm

aws_appautoscaling_policyを呼び出すためのalarmになります。
こちらも増加、減少の両方が必要になります。

resource "aws_cloudwatch_metric_alarm" "alarm_cpu_high" {
  # alarmのnameです。
  # workspaceを利用している場合は、workspaceを利用している場合、workspaceをnameに入れ込み環境ごとに区別できることをお勧めします。
  alarm_name          = "service_name_cpu_utilization_high_${terraform.workspace}"
  
  # しきい値(threshold)以上の時にアラートが鳴るように設定
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "1"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Average"
  
  # CPU使用率のしきい値です。
  # この値以上のときにアラートが上がり、後述のalarm_actionsを実行します。
  threshold           = "80"

  # 監視したい、ECSサービスを指定します。
  dimensions = {
    ClusterName = var.ecs_cluster_name
    ServiceName = var.ecs_service_name
  }
  
  # アラート発生時に実行するpolicyです。ここで、増加ポリシーと減少ポリシーの設定間違えが内容にご注意ください。
  alarm_actions = [aws_appautoscaling_policy.appautoscaling_scale_up.arn]
}

resource "aws_cloudwatch_metric_alarm" "alarm_cpu_low" {
  alarm_name          = "${var.kebab_name}_cpu_utilization_low_${terraform.workspace}"
  
  # しきい値(threshold)以下の時にアラートが鳴るように設定
  comparison_operator = "LessThanOrEqualToThreshold"
  evaluation_periods  = "1"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Average"
  
  # CPU使用率のしきい値です。
  # この値未満のときにアラートが上がり、後述のalarm_actionsを実行します。
  threshold           = var.alarm_cpu_low_threshold

  dimensions = {
    ClusterName = var.ecs_cluster_name
    ServiceName = var.ecs_service_name
  }

  # アラート発生時に実行するpolicyです。ここで、増加ポリシーと減少ポリシーの設定間違えが内容にご注意ください。
  alarm_actions = [aws_appautoscaling_policy.appautoscaling_scale_down.arn]
}

オートスケーリングの設定は以上になります。

テスト

手っ取り早く負荷テストをする場合abコマンドが楽だと思いますが、弊社はGraphqlを採用しておりますので、k6というツールを利用してテストをしていきます。

ここでは簡単にk6の使い方を紹介させていただきます。

インストール

brew install k6

実行ファイルの準備

実行ファイルを適当に現在の作業ディレクトリに作成してください。
記述はjsなので、書き換えたい時はjsのルールに従ってください。

test.js
import { check } from "k6"
import http from "k6/http"

// 呼び出すQueryをこちらに記述してください。
const query = `
query {
  test(
  ){
        results: results{
          id,
	  name
        }
  }
}
`

export default function () {
  // ヘッダー情報はこちらに追加してください。
  const headers = {
    "Content-Type": "application/json"
  }

  const res = http.post(
    // テストを行いたいURIを指定してください。
    "https://hoge.example.com/graphql",
    JSON.stringify({ query: query }),
    { headers: headers }
  )
  check(res, {
    'is_status_200': (r) => r.status === 200
  })
}

実行

以下コマンドでテストの実行が可能となります。

k6 run test.js --vus 10 -d 1h
  • --vusは同時実行ユーザ数で並列で稼働する数になります。
  • -dは実行時間です。今回は1時間を指定してます。

その他細かい実行オプションを設定したい場合は公式のドキュメントをご確認ください。
https://k6.io/docs/using-k6/k6-options/reference/

参考

まとめ

以上で、ECS Fargate環境下でのオートスケーリングの設定が可能になります。
調べてみると意外と簡単で調査自体は半日程度で済みました。
terraformのコードを利用することで、すぐに真似することができますし、
コンソール画面のUI変更が激しい昨今のAWSでは、知らない領域の最初の一歩はterraformで進みやすいなと感じました。

宣伝

弊社では、今まで取り扱っていなかった新しい技術に関しても前向きに進んでおります。
ご興味持っていただけたら以下より応募をお願いいたします。

https://www.wantedly.com/projects/1113570
https://www.wantedly.com/projects/1113544
https://www.wantedly.com/projects/1061116

弊社は人、文化が良いなと個人的には感じておりますのでこちらも併せて読んでいただけますと嬉しいです。
https://spacemarket.co.jp/recruit/engineer/

スペースマーケット Engineer Blog

Discussion