ECS Orchestration Part 3: Autoscaling
Daniele Baggio
Posted on November 13, 2024
This post describes the main types of autoscaling ECS and how to configure them via terraform , providing some examples from which to take inspiration. If you want to learn more about ECS container orchestration you can look at previous articles (Part 1, Part 2).
Amazon ECS offers several autoscaling mechanisms to handle varying workloads for containerized applications. Each type of scaling targets different aspects of the infrastructure to ensure your application remains responsive under load. The primary types of autoscaling in ECS include:
- Service Autoscaling: Adjusts the number of task instances within a specific ECS service.
- Cluster Autoscaling (Managed Scaling): Modifies the number of EC2 instances (hosts) in an ECS cluster when running EC2-backed clusters.
- Target Tracking and Step Scaling Policies: Offers two main policy types to control scaling behavior.
Service Autoscaling
Service Autoscaling automatically scales the number of tasks in an ECS service to meet demand. This is helpful for applications with variable workloads where you want the service to scale automatically based on CPU, memory, or custom CloudWatch metrics.
Terraform Configuration for Service Autoscaling
Define the ECS Service: First, define your ECS service with its properties.
Create Autoscaling Policies: Use Terraform to define the target tracking or step scaling policies for your ECS service.
Attach Autoscaling to ECS Service: Link the ECS service to the autoscaling policy.
resource "aws_ecs_cluster" "ecs_cluster" {
name = "example-cluster"
}
resource "aws_ecs_service" "ecs_service" {
name = "my-service"
cluster = aws_ecs_cluster.example.id
task_definition = aws_ecs_task_definition.ecs_service_task.arn
desired_count = 1
autoscale {
min_capacity = 1
max_capacity = 10
}
}
resource "aws_appautoscaling_target" "app_scaling" {
max_capacity = 10
min_capacity = 1
resource_id = "service/my-cluster/my-service"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
resource "aws_appautoscaling_policy" "cpu_scaling_policy" {
name = "cpu-policy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.app_scaling.resource_id
scalable_dimension = aws_appautoscaling_target.app_scaling.scalable_dimension
service_namespace = aws_appautoscaling_target.app_scaling.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 50
customized_metric_specification {
metric_name = "CPUUtilization"
namespace = "AWS/ECS"
statistic = "Average"
unit = "Percent"
dimensions {
name = "ClusterName"
value = "my-cluster"
}
dimensions {
name = "ServiceName"
value = "my-service"
}
}
}
}
resource "aws_appautoscaling_policy" "memory_scaling_policy" {
name = "memory-policy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.app_scaling.resource_id
scalable_dimension = aws_appautoscaling_target.app_scaling.scalable_dimension
service_namespace = aws_appautoscaling_target.app_scaling.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 50
scale_in_cooldown = 240
scale_out_cooldown = 240
customized_metric_specification {
metric_name = "MemoryUtilization"
namespace = "AWS/ECS"
statistic = "Average"
unit = "Percent"
dimensions {
name = "ClusterName"
value = "my-cluster"
}
dimensions {
name = "ServiceName"
value = "my-service"
}
}
}
}
In this example, the ECS service scales based on CPU and memory usage, maintaining CPU and memory utilization around 50%.
To scale up on memory metrics , look first at this post.
Cluster Autoscaling
Cluster Autoscaling automatically manages the number of EC2 instances within an ECS cluster. This is essential for EC2-backed clusters where additional hosts may be required based on task placement and resource needs.
Define an Auto Scaling Group (ASG): Specify an ASG for your EC2 instances. The ASG handles the scaling of the ECS cluster itself.
Enable Managed Scaling for the ECS Cluster: Use the aws_ecs_cluster resource to define the cluster with managed scaling.
Configure CloudWatch Alarms: CloudWatch alarms are necessary for scaling based on memory or CPU usage thresholds.
resource "aws_ecs_cluster" "my_cluster" {
name = "example-ecs-cluster"
}
data "aws_ami" "ecs_optimized" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-ecs-hvm-*-x86_64-ebs"]
}
}
resource "aws_iam_role" "ecs_instance_role" {
name = "ecsInstanceRole"
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "ec2.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
})
}
resource "aws_iam_role_policy_attachment" "ecs_instance_policy" {
role = aws_iam_role.ecs_instance_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
}
resource "aws_iam_instance_profile" "ecs_instance_profile" {
name = "ecsInstanceProfile"
role = aws_iam_role.ecs_instance_role.name
}
resource "aws_launch_template" "ecs_launch_template" {
name_prefix = "ecs-instance-"
image_id = data.aws_ami.ecs_optimized.id
instance_type = "t3.small"
user_data = base64encode(<<EOF
#!/bin/bash
echo "ECS_CLUSTER=${aws_ecs_cluster.my_cluster.name}" >> /etc/ecs/ecs.config
EOF
)
iam_instance_profile {
name = aws_iam_instance_profile.ecs_instance_profile.name
}
}
resource "aws_autoscaling_group" "ecs_asg" {
desired_capacity = 1
min_size = 1
max_size = 5
launch_template = {
id = aws_launch_template.ecs_launch_template.id
version = "$Latest"
}
vpc_zone_identifier = ["subnet-1", "subnet-2"]
tag {
key = "Name"
value = "ECS Instance"
propagate_at_launch = true
}
tag {
key = "AmazonECSManaged"
value = true
propagate_at_launch = true
}
}
resource "aws_ecs_capacity_provider" "ecs_capacity_provider" {
name = "example-ecs-capacity-provider"
auto_scaling_group_provider {
auto_scaling_group_arn = aws_autoscaling_group.ecs_asg.arn
managed_scaling {
status = "ENABLED"
target_capacity = 75
minimum_scaling_step_size = 1
maximum_scaling_step_size = 4
}
managed_termination_protection = "ENABLED" # Protects tasks from ASG scale-in
}
}
resource "aws_ecs_cluster_capacity_providers" "ecs_cluster_capacity_providers" {
cluster_name = aws_ecs_cluster.my_cluster.name
capacity_providers = [
aws_ecs_capacity_provider.ecs_capacity_provider.name
]
}
This configuration sets up an EC2-backed ECS cluster with cluster autoscaling. Modify the desired_capacity, max_size, and min_size to define how the ASG scales based on resource demands.
Target Tracking vs Step Scaling Policies
Both Target Tracking and Step Scaling Policies control how scaling occurs based on specific metrics.
Target Tracking tries to keep a specified metric at a defined target level. AWS will automatically adjust resources up or down to maintain this target.
Step Scaling adjusts the capacity in steps based on specified thresholds. For example, you can set multiple alarms that trigger different scaling actions based on how far the current value is from the threshold.
resource "aws_appautoscaling_target" "autoscaling_target" {
max_capacity = 1
min_capacity = 5
resource_id = "service/my-service/${aws_ecs_service.service.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
# Use this configuration for Step scaling
resource "aws_appautoscaling_policy" "step_scaling_policy" {
name = "step-scaling-policy"
policy_type = "StepScaling"
resource_id = aws_appautoscaling_target.autoscaling_target.resource_id
scalable_dimension = aws_appautoscaling_target.autoscaling_target.scalable_dimension
service_namespace = aws_appautoscaling_target.autoscaling_target.service_namespace
step_scaling_policy_configuration {
adjustment_type = "ChangeInCapacity"
cooldown = 60
step_adjustment {
metric_interval_lower_bound = 0
scaling_adjustment = 1
}
step_adjustment {
metric_interval_upper_bound = 0
scaling_adjustment = -1
}
}
}
# Use this configuration for Target tracking scaling
resource "aws_appautoscaling_policy" "autoscaling_policy" {
name = "my-service-policy"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.autoscaling_target.resource_id
scalable_dimension = aws_appautoscaling_target.autoscaling_target.scalable_dimension
service_namespace = aws_appautoscaling_target.autoscaling_target.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 50
customized_metric_specification {
metric_name = "CPUUtilization"
namespace = "AWS/ECS"
statistic = "Average"
unit = "Percent"
dimensions {
name = "ClusterName"
value = "my-cluster"
}
dimensions {
name = "ServiceName"
value = "my-service"
}
}
}
}
Summary
- Service Autoscaling: Manages tasks within an ECS service. Use Terraform's aws_appautoscaling_target to set up target tracking and policy definitions.
- Cluster Autoscaling: Expands or shrinks the number of EC2 instances. Set up an Auto Scaling Group and link it to the ECS cluster.
- Scaling Policies: TargetTrackingScaling for maintaining a target metric or StepScaling for responding to metric thresholds.
Using these configurations, you can control and automate your ECS services' behavior based on resource needs, ensuring efficient, cost-effective scaling across various AWS resources.
Posted on November 13, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.