今回初ECS/FargateでAuto Scalingの設定を試してみました。FargateとEC2のAuto Scaling設定違いといえば、インスタンスの縛りがないことで、ECS Cluster内でtaskを自在に配置と管理ができます。なのでデプロイ周りの実装などは考えずに設定が楽になります。また、Auto Scalingの設定はサービスから設定できますが、実際には別リソースということもあり、テストとしてTerraformでCloudWatch Alermと連携してCPUメトリクスでスケールイン/アウトを実装してみました。
※ちなみにEC2のオートスケールはデプロイ含めて手間がかかる。。
オートスケールの概要と設定の流れ
https://aws.amazon.com/jp/blogs/news/automatic-scaling-with-amazon-ecs/
・来ているアプリケーションの負荷にキャパシティを対応させる: ECS ServiceとECS ClusterのAuto Scaling Groupを両方にScaling Policyを使います。必要に応じて、Cluster InstanceとService Taskをスケールアウトさせ、需要が落ち着いたら安全にスケールインさせることで、キャパシティの推測ゲームから抜け出せます。これによって、ロングランな環境で低コストな高可用性を実現できます。
・複数AZのClusterでECSの基盤に高い可用性を持たせる: Zone障害という可能性から守ることができます。Availability Zoneを考慮しているECS SchedulerはCluster上のTaskを管理し、スケールし、分散してくれるので、アーキテクチャは高い可用性を持ちます。
- CloudWatch Alarm設定(CPU 60%でタスク増加)
- ECS/Service AutoScaling 設定 (タスクの最大数2)
- Auto Scaling Policy設定
- 負荷テスト
Terraform
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm
- autoscale.tf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
data "aws_iam_role" "ecs_service_autoscaling" { #name = aws_iam_role.ecs_autoscale_role.name name = "AWSServiceRoleForApplicationAutoScaling_ECSService" } resource "aws_appautoscaling_target" "wordpress_ecs_target" { service_namespace = "ecs" resource_id = "service/${aws_ecs_cluster.wordpress.name}/${aws_ecs_service.wordpress.name}" scalable_dimension = "ecs:service:DesiredCount" role_arn = data.aws_iam_role.ecs_service_autoscaling.arn min_capacity = 1 max_capacity = 2 } resource "aws_appautoscaling_policy" "wordpress_scale_up" { name = "wordpress_scale_up" service_namespace = "ecs" resource_id = "service/${aws_ecs_cluster.wordpress.name}/${aws_ecs_service.wordpress.name}" scalable_dimension = "ecs:service:DesiredCount" step_scaling_policy_configuration { adjustment_type = "ChangeInCapacity" cooldown = 120 metric_aggregation_type = "Average" step_adjustment { metric_interval_lower_bound = 0 scaling_adjustment = 1 } } depends_on = [aws_appautoscaling_target.wordpress_ecs_target] } resource "aws_appautoscaling_policy" "wordpress_scale_down" { name = "wordpress_scale_down" service_namespace = "ecs" resource_id = "service/${aws_ecs_cluster.wordpress.name}/${aws_ecs_service.wordpress.name}" scalable_dimension = "ecs:service:DesiredCount" step_scaling_policy_configuration { adjustment_type = "ChangeInCapacity" cooldown = 120 metric_aggregation_type = "Average" step_adjustment { metric_interval_upper_bound = 0 scaling_adjustment = -1 } } depends_on = [aws_appautoscaling_target.wordpress_ecs_target] } resource "aws_cloudwatch_metric_alarm" "wordpress_cpu_high" { alarm_name = "wordpress_cpu_utilization_high" comparison_operator = "GreaterThanOrEqualToThreshold" evaluation_periods = "1" metric_name = "CPUUtilization" namespace = "AWS/ECS" period = "60" statistic = "Average" threshold = "60" dimensions = { ClusterName = aws_ecs_cluster.wordpress.name ServiceName = aws_ecs_service.wordpress.name } alarm_actions = [aws_appautoscaling_policy.wordpress_scale_up.arn] } resource "aws_cloudwatch_metric_alarm" "wordpress_cpu_low" { alarm_name = "wordpress_cpu_utilization_low" comparison_operator = "LessThanOrEqualToThreshold" evaluation_periods = "1" metric_name = "CPUUtilization" namespace = "AWS/ECS" period = "60" statistic = "Average" threshold = "30" dimensions = { ClusterName = aws_ecs_cluster.wordpress.name ServiceName = aws_ecs_service.wordpress.name } alarm_actions = [aws_appautoscaling_policy.wordpress_scale_down.arn] } |
テストとして、WordPressコンテナでCPU 60%以上負荷がかかったらコンテナ数(タスク)2台にしてCPU 30%以下でコンテナ数(タスク)1台にするよう作ってみました。使用するResourceは aws_appautoscaling_target
と aws_cloudwatch_metric_alarm
になります。実際に動作確認してみましょう。
- iam.tf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
## AutoScaling_ECSService resource "aws_iam_role" "ecs_autoscale_role" { name = "ecs_autoscale_role" assume_role_policy = file("files/assume_role_policy/autoscale.json") } resource "aws_iam_policy" "ecs_autoscale_role" { name = "AWSApplicationAutoscalingECSService_Policy" description = "AWSApplicationAutoscalingECSService_Policy" policy = file("files/assume_role_policy/autoacaling-ecservice.json") } resource "aws_iam_role_policy_attachment" "ecs_autoscale_role_attach" { role = aws_iam_role.ecs_autoscale_role.name policy_arn = aws_iam_policy.ecs_autoscale_role.arn } |
- files/assume_role_policy/autoscale.json
1 2 3 4 5 6 7 8 9 10 11 12 13 |
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "application-autoscaling.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } |
- files/assume_role_policy/autoacaling-ecservice.json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ecs:DescribeServices", "ecs:UpdateService", "cloudwatch:PutMetricAlarm", "cloudwatch:DescribeAlarms", "cloudwatch:DeleteAlarms" ], "Resource": [ "*" ] } ] } |
他にもTerraformのバグなのかわかりませんが、IAMでService Auto Scaling用のIAM ロールを指定すると、以下のエラーが出てしまった場合は独自のロールを作成して適用すればいいんですが、なぜかデフォルトの AWSServiceRoleForApplicationAutoScaling_ECSService
のロールが新規できてしまい、サービスから独自のロールに更新してもデフォのロールに戻ってしまうので、一旦独自ロールを作成して適用してから AWSServiceRoleForApplicationAutoScaling_ECSService
に戻すようにしました。これはハマった…
1 2 3 4 5 |
Error: error reading IAM Role (AWSServiceRoleForApplicationAutoScaling_ECSService): NoSuchEntity: The role with name AWSServiceRoleForApplicationAutoScaling_ECSService cannot be found. status code: 404, request id: xxxxxxxxxxxxxxxxxxxxxxxxx on autoscale.tf line 86, in data "aws_iam_role" "ecs_service_autoscaling": 86: data "aws_iam_role" "ecs_service_autoscaling" { |
1 2 3 4 5 6 7 8 9 10 11 |
# aws_appautoscaling_target.wordpress_ecs_target will be updated in-place ~ resource "aws_appautoscaling_target" "wordpress_ecs_target" { id = "service/wordpress/wordpress" max_capacity = 2 min_capacity = 1 resource_id = "service/wordpress/wordpress" ~ role_arn = "arn:aws:iam::xxxxxxxx:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService" -> "arn:aws:iam::xxxxxxxx:role/ecs_autoscale_role" scalable_dimension = "ecs:service:DesiredCount" service_namespace = "ecs" } Plan: 0 to add, 1 to change, 0 to destroy. |
補足としてはECS サービスの自動スケーリングを有効にすると、サービスにリンクされたロールが AWSServiceRoleForApplicationAutoScaling_ECSService
という名前で作成されます。なので手動で作る場合はIAMロールを独自で作成する必要はないので、Terraformだと上記のように対応しないとダメそうですね。ここらへん分かる方連絡おねしゃす。
※追記
サービスリンクロールを手動で作成する必要はありません。Application Auto Scaling は、ユーザーが
RegisterScalableTarget
を呼び出す時に、適切なサービスリンクロールを作成します。例えば、Amazon ECS サービスのオートスケーリングをセットアップする場合は、Application Auto Scaling がAWSServiceRoleForApplicationAutoScaling_ECSService
ロールを作成します。
そもそもオートスケール用のIAM Roleは自動作成されるので、指定しなくてもいいことが分かった…なので以下先頭に追加するだけで問題ないです。
1 2 3 |
data "aws_iam_role" "ecs_service_autoscaling" { name = "AWSServiceRoleForApplicationAutoScaling_ECSService" } |
負荷テスト
1 |
$ ab -n 100000000 -c 10000 https://hoge.com/ |
Totalリクエスト数100000000、同時アクセス数10000てabテストします。これは相当な負荷だ…AWSに上限申請しないと。
- CPU 60%超える
- タスクが2台になる
- CPU 30%になる
- タスクが1台になる
まとめ
ECS/FargateでAutoScale試してみたんだけど、なんて便利なの!!CloudWatchAlarmと連携してCPUメトリクスでスケールイン/アウトするだけだった。Terraform化もサクッと。後でブログ書こう📖
— adachin👾SRE (@adachin0817) March 8, 2021
特にハマることなくTerraformでサクッと実装することができました。簡単にオートスケーリングの設定が可能なので、Fargateの良さをさらに発見することができました。本番はもろもろ調整する必要があるので設定せねば!ちなみに60%だとECSの立ち上がりが遅いので20%の方がベストですね。
0件のコメント