ECS＋FargateのAutoScaling設定をTerraformで定義する

# はじめに
ECS＋Fargateでサーバレス＆運用省エネにシステムを構築しているのだから、やはりここは負荷量に応じた運用負荷も軽減したい。

TerraformでサクッとAutoScaling設定をしてみよう。

なお、本記事ではキャパシティプロバイダは使用しないケースで対応している。
また、マルチAZ構成を前提としてTerraformを書いている。Fargateの前段に配置するELBは、クロスゾーン負荷分散を有効にしておかないと、AutoScalingで1台増設が走ったときに正しく分散されないので注意(クロスゾーン負荷分散はNLBのみデフォルトでOFF)。

# ECS＋FargateのTerraform設定
今回はこの部分は本筋ではないので割愛する。
自分の過去記事では、↓このあたりが参考になると思う。

[Terraformの初心者がAmazon EC2に実行環境を作ってECS Fargateなアプリの自動構築をしてみる](https://qiita.com/neruneruo/items/d5e58b4013debdf9ebbe)

上記の通り、マルチAZ前提であるため、タスクの ```desired_count``` は2にしておく。

# AutoScaling Policyの設定
以下のように、```aws_appautoscaling_target``` と ```aws_appautoscaling_policy``` で構成されている。今回は、平均CPU使用率に応じたスケールアウト、スケールインを設定する。


```HCL
resource "aws_appautoscaling_target" "ecsfargate" {
  service_namespace  = "ecs"
  resource_id        = "service/${aws_ecs_cluster.ecsfargate.name}/${aws_ecs_service.ecsfargate_service.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  min_capacity       = 2
  max_capacity       = 4
}

resource "aws_appautoscaling_policy" "ecsfargate_scale_out" {
  name               = "scale_out"
  policy_type        = "StepScaling"
  service_namespace  = aws_appautoscaling_target.ecsfargate.service_namespace
  resource_id        = aws_appautoscaling_target.ecsfargate.resource_id
  scalable_dimension = aws_appautoscaling_target.ecsfargate.scalable_dimension

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = 60
    metric_aggregation_type = "Average"

    step_adjustment {
      metric_interval_lower_bound = 0
      scaling_adjustment          = 1
    }
  }
}

resource "aws_appautoscaling_policy" "ecsfargate_scale_in" {
  name               = "scale_in"
  policy_type        = "StepScaling"
  service_namespace  = aws_appautoscaling_target.ecsfargate.service_namespace
  resource_id        = aws_appautoscaling_target.ecsfargate.resource_id
  scalable_dimension = aws_appautoscaling_target.ecsfargate.scalable_dimension

  step_scaling_policy_configuration {
    adjustment_type         = "ChangeInCapacity"
    cooldown                = 60
    metric_aggregation_type = "Average"

    step_adjustment {
      metric_interval_upper_bound = 0
      scaling_adjustment          = -1
    }
  }
}
```

上記が理解できたら、今度は、AutoScaling を発動するための CloudWatchメトリクスのアラームを設定する。
ecsfargate_cpu_high が、ECSのサービスのCPU使用率が75%以上になったときに発動、ecsfargate_cpu_low が、ECSのサービスのCPU使用率が75%以下になったときに発動する。

```HCL
resource "aws_cloudwatch_metric_alarm" "ecsfargate_cpu_high" {
  alarm_name          = "cpu_utilization_high"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Average"
  threshold           = "75"

  dimensions = {
    ClusterName = aws_ecs_cluster.ecsfargate.name
    ServiceName = aws_ecs_service.ecsfargate_service.name
  }

  alarm_actions = [
    aws_appautoscaling_policy.ecsfargate_scale_out.arn
  ]
}

resource "aws_cloudwatch_metric_alarm" "ecsfargate_cpu_low" {
  alarm_name          = "cpu_utilization_low"
  comparison_operator = "LessThanOrEqualToThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Average"
  threshold           = "25"

  dimensions = {
    ClusterName = aws_ecs_cluster.ecsfargate.name
    ServiceName = aws_ecs_service.ecsfargate_service.name
  }

  alarm_actions = [
    aws_appautoscaling_policy.ecsfargate_scale_in.arn
  ]
}
```

# 設定後の動作
設定すると、以下のようなCloudWatchアラームの設定が入る。
※キャプチャは、実際に負荷を入れてスケールアウトが発動したもの

![キャプチャ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/8cdd8f31-6fc8-4d7c-8e2b-d2dd6c49dc9f.png)

実際にスケールアウトが発動すると、マネージメントコンソールに以下のログが出力される。
一番上の行は、スケールアウトによりECSサービス全体のCPU使用率が下がり、OKの状態になった際のものだ。

![キャプチャ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/4ddf4048-92ad-fa88-7626-e9c2987fc022.png)

スケールインするときも同様、以下のようになる。

![キャプチャ3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/f566d0c7-70b1-22a5-6d8c-ab14c1011169.png)

![キャプチャ4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/f637d332-ec46-0ec4-1e9d-049616e8ae82.png)

ECSのイベントログも、以下のような感じで、2タスク単位で動いているのが分かる。

![キャプチャ6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111314/c508fad5-ed1a-aac0-0d23-7c6f52ecf31c.png)

これで、トラフィック量に応じて自由にスケールアウト/インできるようになった！