Created
August 14, 2020 11:32
-
-
Save sschrijver/9f29466097de17f326c945dab7aad8ba to your computer and use it in GitHub Desktop.
Scaling fargate based on SQS queue items
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| provider "aws" { | |
| profile = var.profile_name | |
| region = var.region | |
| } | |
| data "aws_ecs_cluster" "ecs_cluster" { | |
| cluster_name = var.ecs_cluster_name | |
| } | |
| resource "aws_iam_role" "ecs_task_execution_role" { | |
| name = "ecsTaskExecutionRole-${var.service_name}" | |
| assume_role_policy = <<ASSUME_ROLE_POLICY | |
| { | |
| "Version": "2012-10-17", | |
| "Statement": [ | |
| { | |
| "Sid": "", | |
| "Effect": "Allow", | |
| "Principal": { | |
| "Service": "ecs-tasks.amazonaws.com" | |
| }, | |
| "Action": "sts:AssumeRole" | |
| } | |
| ] | |
| } | |
| ASSUME_ROLE_POLICY | |
| } | |
| data "aws_iam_policy" "amazon_ecs_task_execution_role_policy" { | |
| arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" | |
| } | |
| resource "aws_iam_role_policy_attachment" "policy_role_attachment" { | |
| role = aws_iam_role.ecs_task_execution_role.name | |
| policy_arn = data.aws_iam_policy.amazon_ecs_task_execution_role_policy.arn | |
| } | |
| resource "aws_iam_role" "task_role" { | |
| name = "ecsTaskRole-${var.service_name}" | |
| assume_role_policy = <<ASSUME_ROLE_POLICY | |
| { | |
| "Version": "2012-10-17", | |
| "Statement": [ | |
| { | |
| "Sid": "", | |
| "Effect": "Allow", | |
| "Principal": { | |
| "Service": "ecs-tasks.amazonaws.com" | |
| }, | |
| "Action": "sts:AssumeRole" | |
| } | |
| ] | |
| } | |
| ASSUME_ROLE_POLICY | |
| } | |
| resource "aws_iam_policy" "ecs_task_role_policy" { | |
| name = "ecsTaskRolePolicy-${var.service_name}" | |
| policy = <<POLICY | |
| { | |
| "Version": "2012-10-17", | |
| "Statement": [ | |
| ] | |
| } | |
| POLICY | |
| } | |
| resource "aws_iam_role_policy_attachment" "task_role_policy_attachment" { | |
| role = aws_iam_role.task_role.name | |
| policy_arn = aws_iam_policy.ecs_task_role_policy.arn | |
| } | |
| resource "aws_cloudwatch_log_group" "ecs_log_group" { | |
| name = "/aws/ecs/${var.service_name}" | |
| } | |
| resource "aws_ecs_task_definition" "task_definition" { | |
| family = var.service_name | |
| requires_compatibilities = [ | |
| "FARGATE"] | |
| network_mode = "awsvpc" | |
| cpu = var.cpu | |
| memory = var.memory | |
| execution_role_arn = aws_iam_role.ecs_task_execution_role.arn | |
| task_role_arn = aws_iam_role.task_role.arn | |
| container_definitions = <<TASK_DEFINITION | |
| [ | |
| { | |
| "essential": true, | |
| "image": "${var.image_url}:${var.image_tag}", | |
| "name": "${var.service_name}", | |
| "logConfiguration": { | |
| "logDriver": "awslogs", | |
| "options": { | |
| "awslogs-region": "${var.region}", | |
| "awslogs-group": "${aws_cloudwatch_log_group.ecs_log_group.name}", | |
| "awslogs-stream-prefix": "${var.service_name}" | |
| } | |
| } | |
| } | |
| ] | |
| TASK_DEFINITION | |
| } | |
| data "aws_vpc" "vpc" { | |
| id = var.vpc_id | |
| } | |
| resource "aws_security_group" "security_group" { | |
| name = var.service_name | |
| vpc_id = data.aws_vpc.vpc.id | |
| egress { | |
| from_port = 0 | |
| to_port = 0 | |
| protocol = "-1" | |
| cidr_blocks = [ | |
| "0.0.0.0/0"] | |
| } | |
| tags = { | |
| Name = var.service_name | |
| } | |
| } | |
| resource "aws_ecs_service" "service" { | |
| name = var.service_name | |
| cluster = data.aws_ecs_cluster.ecs_cluster.id | |
| task_definition = aws_ecs_task_definition.task_definition.id | |
| desired_count = 0 | |
| launch_type = "FARGATE" | |
| network_configuration { | |
| subnets = var.fargate_subnets | |
| security_groups = [ | |
| aws_security_group.security_group.id] | |
| } | |
| } | |
| data "aws_iam_role" "ecs_autoscaling_role" { | |
| name = "AWSServiceRoleForAutoScaling" | |
| } | |
| resource "aws_appautoscaling_target" "ecs_target" { | |
| max_capacity = 10 | |
| min_capacity = 0 | |
| resource_id = "service/${data.aws_ecs_cluster.ecs_cluster.cluster_name}/${var.service_name}" | |
| role_arn = data.aws_iam_role.ecs_autoscaling_role.arn | |
| scalable_dimension = "ecs:service:DesiredCount" | |
| service_namespace = "ecs" | |
| } | |
| resource "aws_appautoscaling_policy" "scale_up_fargate" { | |
| policy_type = "StepScaling" | |
| name = "sqs-scaling-up-${var.service_name}" | |
| resource_id = aws_appautoscaling_target.ecs_target.resource_id | |
| scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension | |
| service_namespace = aws_appautoscaling_target.ecs_target.service_namespace | |
| step_scaling_policy_configuration { | |
| adjustment_type = "ExactCapacity" | |
| metric_aggregation_type = "Average" | |
| step_adjustment { | |
| metric_interval_lower_bound = 0 | |
| metric_interval_upper_bound = 500 | |
| scaling_adjustment = 1 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 500 | |
| metric_interval_upper_bound = 1000 | |
| scaling_adjustment = 2 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 1000 | |
| metric_interval_upper_bound = 1500 | |
| scaling_adjustment = 3 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 1500 | |
| metric_interval_upper_bound = 2000 | |
| scaling_adjustment = 4 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 2000 | |
| metric_interval_upper_bound = 2500 | |
| scaling_adjustment = 5 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 2500 | |
| metric_interval_upper_bound = 3000 | |
| scaling_adjustment = 6 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 3000 | |
| metric_interval_upper_bound = 3500 | |
| scaling_adjustment = 7 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 3500 | |
| metric_interval_upper_bound = 4000 | |
| scaling_adjustment = 8 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 4000 | |
| metric_interval_upper_bound = 4500 | |
| scaling_adjustment = 9 | |
| } | |
| step_adjustment { | |
| metric_interval_lower_bound = 4500 | |
| scaling_adjustment = 10 | |
| } | |
| } | |
| } | |
| resource "aws_appautoscaling_policy" "scale_down_fargate" { | |
| policy_type = "StepScaling" | |
| name = "sqs-scaling-down-${var.service_name}" | |
| resource_id = aws_appautoscaling_target.ecs_target.resource_id | |
| scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension | |
| service_namespace = aws_appautoscaling_target.ecs_target.service_namespace | |
| step_scaling_policy_configuration { | |
| adjustment_type = "ExactCapacity" | |
| metric_aggregation_type = "Average" | |
| step_adjustment { | |
| metric_interval_upper_bound = 0 | |
| scaling_adjustment = 0 | |
| } | |
| } | |
| } | |
| resource "aws_cloudwatch_metric_alarm" "sqs_scale_out" { | |
| alarm_name = "SQS-ScaleOut-${var.service_name}" | |
| comparison_operator = "GreaterThanOrEqualToThreshold" | |
| evaluation_periods = "1" | |
| metric_name = "ApproximateNumberOfMessagesVisible" | |
| namespace = "AWS/SQS" | |
| period = "60" | |
| threshold = "1" | |
| statistic = "Sum" | |
| alarm_description = "SQS-ScaleOut-${var.service_name}" | |
| insufficient_data_actions = [] | |
| alarm_actions = [ | |
| aws_appautoscaling_policy.scale_up_fargate.arn] | |
| dimensions = { | |
| QueueName = var.queue_name | |
| } | |
| } | |
| resource "aws_cloudwatch_metric_alarm" "sqs_scale_in" { | |
| alarm_name = "SQS-ScaleIn-${var.service_name}" | |
| comparison_operator = "LessThanThreshold" | |
| evaluation_periods = "1" | |
| metric_name = "ApproximateNumberOfMessagesVisible" | |
| namespace = "AWS/SQS" | |
| period = "60" | |
| threshold = "1" | |
| statistic = "Sum" | |
| alarm_description = "SQS-ScaleIn-${var.service_name}" | |
| alarm_actions = [ | |
| aws_appautoscaling_policy.scale_down_fargate.arn] | |
| dimensions = { | |
| QueueName = var.queue_name | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is fabulous, thanks for taking the time to write it up.