From dec2006fb5ced9f86f319fcf4cd6988db48b248b Mon Sep 17 00:00:00 2001 From: Chris Wright Date: Fri, 29 Dec 2023 13:07:11 +0000 Subject: [PATCH] ECS Cluster time based autoscaling * Allows configuring time based autoscaling for the Infrastructure ECS Cluster's autoscaling group. * Cron expressions can be provided to set the desired capacity to the min or max sizes. Custom scaling sizes can also be provided, to set the min/max sizes for a given cron expression (in which case the min size will be set as the desired capacity) --- README.md | 6 ++++ ...r-infrastructure-autoscaling-time-based.tf | 32 +++++++++++++++++++ locals.tf | 5 +++ variables.tf | 21 ++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 ecs-cluster-infrastructure-autoscaling-time-based.tf diff --git a/README.md b/README.md index b66c361..235281b 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,9 @@ This project creates and manages resources within an AWS account for infrastruct | [aws_athena_workgroup.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/athena_workgroup) | resource | | [aws_autoscaling_group.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group) | resource | | [aws_autoscaling_lifecycle_hook.infrastructure_ecs_cluster_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_lifecycle_hook) | resource | +| [aws_autoscaling_schedule.ecs_infrastructure_time_based_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_schedule) | resource | +| [aws_autoscaling_schedule.ecs_infrastructure_time_based_max](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_schedule) | resource | +| [aws_autoscaling_schedule.ecs_infrastructure_time_based_min](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_schedule) | resource | | [aws_cloudwatch_log_group.ecs_cluster_infrastructure_draining_lambda_log_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | | [aws_cloudwatch_log_group.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | | [aws_default_network_acl.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_network_acl) | resource | @@ -121,6 +124,9 @@ This project creates and manages resources within an AWS account for infrastruct | [infrastructure\_dockerhub\_email](#input\_infrastructure\_dockerhub\_email) | Dockerhub email | `string` | n/a | yes | | [infrastructure\_dockerhub\_token](#input\_infrastructure\_dockerhub\_token) | Dockerhub token which has permissions to pull images | `string` | n/a | yes | | [infrastructure\_ecs\_cluster\_ami\_version](#input\_infrastructure\_ecs\_cluster\_ami\_version) | AMI version for ECS cluster instances (amzn2-ami-ecs-hvm-) | `string` | n/a | yes | +| [infrastructure\_ecs\_cluster\_autoscaling\_time\_based\_custom](#input\_infrastructure\_ecs\_cluster\_autoscaling\_time\_based\_custom) | List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired. |
list(
object({
cron = string
min = number
max = number
})
)
| n/a | yes | +| [infrastructure\_ecs\_cluster\_autoscaling\_time\_based\_max](#input\_infrastructure\_ecs\_cluster\_autoscaling\_time\_based\_max) | List of cron expressions to scale the ECS cluster to the configured max size | `list(string)` | n/a | yes | +| [infrastructure\_ecs\_cluster\_autoscaling\_time\_based\_min](#input\_infrastructure\_ecs\_cluster\_autoscaling\_time\_based\_min) | List of cron expressions to scale the ECS cluster to the configured min size | `list(string)` | n/a | yes | | [infrastructure\_ecs\_cluster\_draining\_lambda\_enabled](#input\_infrastructure\_ecs\_cluster\_draining\_lambda\_enabled) | Enable the Lambda which ensures all containers have drained before terminating ECS cluster instances | `bool` | n/a | yes | | [infrastructure\_ecs\_cluster\_draining\_lambda\_log\_retention](#input\_infrastructure\_ecs\_cluster\_draining\_lambda\_log\_retention) | Log retention for the ECS cluster draining Lambda | `number` | n/a | yes | | [infrastructure\_ecs\_cluster\_ebs\_docker\_storage\_volume\_size](#input\_infrastructure\_ecs\_cluster\_ebs\_docker\_storage\_volume\_size) | Size of EBS volume for Docker storage on the infrastructure ECS instances | `number` | n/a | yes | diff --git a/ecs-cluster-infrastructure-autoscaling-time-based.tf b/ecs-cluster-infrastructure-autoscaling-time-based.tf new file mode 100644 index 0000000..4504d7c --- /dev/null +++ b/ecs-cluster-infrastructure-autoscaling-time-based.tf @@ -0,0 +1,32 @@ +resource "aws_autoscaling_schedule" "ecs_infrastructure_time_based_max" { + for_each = local.enable_infrastructure_ecs_cluster ? local.infrastructure_ecs_cluster_autoscaling_time_based_max : [] + + autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name + scheduled_action_name = "${local.resource_prefix}-time-based-max ${each.value}" + desired_capacity = local.infrastructure_ecs_cluster_max_size + min_size = -1 + max_size = -1 + recurrence = each.value +} + +resource "aws_autoscaling_schedule" "ecs_infrastructure_time_based_min" { + for_each = local.enable_infrastructure_ecs_cluster ? local.infrastructure_ecs_cluster_autoscaling_time_based_min : [] + + autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name + scheduled_action_name = "${local.resource_prefix}-time-based-min ${each.value}" + desired_capacity = local.infrastructure_ecs_cluster_min_size + min_size = -1 + max_size = -1 + recurrence = each.value +} + +resource "aws_autoscaling_schedule" "ecs_infrastructure_time_based_custom" { + for_each = local.enable_infrastructure_ecs_cluster ? local.infrastructure_ecs_cluster_autoscaling_time_based_custom : {} + + autoscaling_group_name = aws_autoscaling_group.infrastructure_ecs_cluster[0].name + scheduled_action_name = "${local.resource_prefix}-time-based-custom ${each.value["cron"]} ${each.value["min"]}-${each.value["max"]}" + desired_capacity = each.value["min"] + min_size = each.value["min"] + max_size = each.value["max"] + recurrence = each.value["cron"] +} diff --git a/locals.tf b/locals.tf index 38f9f1d..611b1ad 100644 --- a/locals.tf +++ b/locals.tf @@ -107,6 +107,11 @@ locals { infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime + infrastructure_ecs_cluster_autoscaling_time_based_max = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_max) + infrastructure_ecs_cluster_autoscaling_time_based_min = toset(var.infrastructure_ecs_cluster_autoscaling_time_based_min) + infrastructure_ecs_cluster_autoscaling_time_based_custom = { + for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : "${custom["min"]}-${custom["max"]} ${custom["cron"]}" => custom + } infrastructure_ecs_cluster_user_data = base64encode( templatefile("ec2-userdata/ecs-instance.tpl", { docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name, diff --git a/variables.tf b/variables.tf index cbdf658..92c9d28 100644 --- a/variables.tf +++ b/variables.tf @@ -264,3 +264,24 @@ variable "infrastructure_ecs_cluster_max_instance_lifetime" { description = "Maximum lifetime in seconds of an instance within the ECS cluster" type = number } + +variable "infrastructure_ecs_cluster_autoscaling_time_based_max" { + description = "List of cron expressions to scale the ECS cluster to the configured max size" + type = list(string) +} + +variable "infrastructure_ecs_cluster_autoscaling_time_based_min" { + description = "List of cron expressions to scale the ECS cluster to the configured min size" + type = list(string) +} + +variable "infrastructure_ecs_cluster_autoscaling_time_based_custom" { + description = "List of objects with min/max sizes and cron expressions to scale the ECS cluster. Min size will be used as desired." + type = list( + object({ + cron = string + min = number + max = number + }) + ) +}