ecs (terraform)

Reference

Deploy a service into an ECS cluster behind a public load balancer

Includes scale in (decrease) and scale out (increase) in CloudFormation format.

https://github.com/nathanpeck/ecs-cloudformation/blob/master/service/service-ec2-public-lb.yml


ECS (Fargate) with ALB Deployment Using Terraform — Part 3

Includes security groups for load balancer, ecs, etc.

https://medium.com/the-cloud-journal/ecs-fargate-with-alb-deployment-using-terraform-part-3-eb52309fdd8f

Sample: ECS cluster

modules/ecs/ecs.tf

resource "aws_ecs_cluster" "cluster" {

  name = var.ecs_cluster_name

  setting {

    name  = "containerInsights" #CloudWatch Container Insights

    value = "disabled"          #Additional charges, only if needed, eg: Dashboard container specific

  }

}

Sample: ECS autoscaling by memory (target tracking) and cpu (step)

Tested w/ Terraform AWS provider v5.x.x

main.tf

  ###Scale mem false to disable or true to enable

  is_mem_scale           = true #scale task by memory usage

  mem_target_value       = 40   #target value of scale task by memory usage (%)

  mem_scale_in_cooldown  = 300  #cool down time of scale in (decrease) task by memory usage

  mem_scale_out_cooldown = 300  #cool down time of scale out (increase) task by memory usage


  ###Scale cpu false to disable or true to enable

  is_cpu_scale           = true #scale task by cpu usage

  cpu_target_value       = 40   #target value of scale task by cpu usage (%)

  cpu_scale_in_cooldown  = 300  #cool down time of scale in (decrease) task by cpu usage

  cpu_scale_out_cooldown = 300  #cool down time of scale out (increase) task by cpu usage


  ###Time inactivity to desire

  inactivity = true

ecs.tf

# -------------------------------------

#  Auto Scaling Target

# -------------------------------------

resource "aws_appautoscaling_target" "main" {

  count      = var.inactivity || var.is_cpu_scale || var.is_mem_scale ? 1 : 0

  depends_on = [aws_ecs_service.service]


  max_capacity       = var.task_max_count

  min_capacity       = var.task_desired_count

  resource_id        = "service/${var.ecs_cluster_name}/${var.ecs_service_name}"

  scalable_dimension = "ecs:service:DesiredCount"

  service_namespace  = "ecs"

}



# ----------------------------------------

#  Auto Scaling Policy (ECS desired tasks)

# ----------------------------------------

resource "aws_appautoscaling_policy" "cpu_scale_down" {

  count      = var.is_cpu_scale ? 1 : 0

  depends_on = [aws_appautoscaling_target.main]


  name               = "scale/${local.env}/${local.ci}/down"

  policy_type        = "StepScaling" #"TargetTrackingScaling"

  resource_id        = aws_appautoscaling_target.main[0].resource_id

  scalable_dimension = aws_appautoscaling_target.main[0].scalable_dimension

  service_namespace  = aws_appautoscaling_target.main[0].service_namespace

  step_scaling_policy_configuration {

    adjustment_type = "ChangeInCapacity"

    step_adjustment {

      metric_interval_upper_bound = 0

      scaling_adjustment          = -1

    }

    metric_aggregation_type = "Maximum"

    cooldown                = var.cpu_scale_in_cooldown

  }

}


resource "aws_appautoscaling_policy" "cpu_scale_up" {

  count      = var.is_cpu_scale ? 1 : 0

  depends_on = [aws_appautoscaling_target.main]


  name               = "scale/${local.env}/${local.ci}/up"

  policy_type        = "StepScaling" #"TargetTrackingScaling"

  resource_id        = aws_appautoscaling_target.main[0].resource_id

  scalable_dimension = aws_appautoscaling_target.main[0].scalable_dimension

  service_namespace  = aws_appautoscaling_target.main[0].service_namespace

  step_scaling_policy_configuration {

    adjustment_type = "ChangeInCapacity"

    step_adjustment {

      metric_interval_lower_bound = 0

      metric_interval_upper_bound = 15

      scaling_adjustment          = 1

    }

    step_adjustment {

      metric_interval_lower_bound = 15

      metric_interval_upper_bound = 25

      scaling_adjustment          = 2

    }

    step_adjustment {

      metric_interval_lower_bound = 25

      scaling_adjustment          = 3

    }

    metric_aggregation_type = "Maximum"

    cooldown                = var.cpu_scale_out_cooldown

  }

}


resource "aws_cloudwatch_metric_alarm" "low_cpu_usage_alarm" {

  count = var.is_cpu_scale ? 1 : 0


  alarm_name          = "${local.env}-${local.ci}-low-cpu-fargate"

  comparison_operator = "LessThanOrEqualToThreshold"

  evaluation_periods  = "4"

  metric_name         = "CPUUtilization"

  namespace           = "AWS/ECS"

  period              = "10" # In seconds. Valid values are 10, 30, or any multiple of 60

  statistic           = "Average"

  threshold           = var.cpu_target_value


  dimensions = {

    "ClusterName" = aws_ecs_cluster.jboss.name

    "ServiceName" = aws_ecs_service.service.name

  }


  alarm_description         = "Low CPU utilization for service ${local.env}-${local.ci}"

  alarm_actions             = [aws_appautoscaling_policy.cpu_scale_down[0].arn]

  insufficient_data_actions = [] #(Optional) 

}


resource "aws_cloudwatch_metric_alarm" "high_cpu_usage_alarm" {

  count = var.is_cpu_scale ? 1 : 0


  alarm_name          = "${local.env}-${local.ci}-high-cpu-fargate"

  comparison_operator = "GreaterThanThreshold"

  evaluation_periods  = "4"

  metric_name         = "CPUUtilization"

  namespace           = "AWS/ECS"

  period              = "10" # In seconds. Valid values are 10, 30, or multiple of 60

  statistic           = "Maximum"

  threshold           = var.cpu_target_value


  dimensions = {

    "ClusterName" = aws_ecs_cluster.jboss.name

    "ServiceName" = aws_ecs_service.service.name

  }



  alarm_description         = "High CPU utilization for service ${local.env}-${local.ci}"

  alarm_actions             = [aws_appautoscaling_policy.cpu_scale_up[0].arn]

  insufficient_data_actions = [] #(Optional) 

}



# -------------------------------------

#  Auto Scaling Policy (Memory)

# -------------------------------------

resource "aws_appautoscaling_policy" "mem" {

  count      = var.is_mem_scale ? 1 : 0

  depends_on = [aws_appautoscaling_target.main]


  name               = "memory"

  policy_type        = "TargetTrackingScaling"

  resource_id        = aws_appautoscaling_target.main[0].resource_id

  scalable_dimension = aws_appautoscaling_target.main[0].scalable_dimension

  service_namespace  = aws_appautoscaling_target.main[0].service_namespace


  target_tracking_scaling_policy_configuration {

    predefined_metric_specification {

      predefined_metric_type = "ECSServiceAverageMemoryUtilization"

    }


    target_value       = var.mem_target_value

    scale_in_cooldown  = var.mem_scale_in_cooldown

    scale_out_cooldown = var.mem_scale_out_cooldown

  }

}