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
Includes security groups for load balancer, ecs, etc.
https://hub.docker.com/r/testcontainers/helloworld
docker pull docker.io/testcontainers/helloworld
http://localhost:8080
http://localhost:8080/ping
http://localhost:8080/uuid
------------------
Push to AWS ECR
Tag image:
docker tag docker.io/testcontainers/helloworld 123456789012.dkr.ecr.eu-west-1.amazonaws.com/myapp_back:latest
Login:
aws ecr get-login-password --region eu-west-1 | docker login --username AWS --password-stdin 123456789012.dkr.ecr.eu-west-1.amazonaws.com
Push:
docker push 123456789012.dkr.ecr.eu-west-1.amazonaws.com/myapp_back:latest
== Force new deployment
aws ecs update-service --cluster dev-myapp-ecs-cluster --service dev-myapp-ecs-service --task-definition dev-myapp_back --force-new-deployment
Note: Ensure the Load Balancing Target Groups health check succeeds (change it if needed)
Eg: strategies (untested)
resource "aws_ecs_service"
enable_execute_command = true #(Optional) Whether to enable Amazon ECS Exec for the tasks within the service
resource "aws_ecs_task_definition"
must have block runtime_platform:
runtime_platform { #This block is crucial for enabling executeCommand (OS & arch)
operating_system_family = "LINUX" # or "WINDOWS_SERVER_2019_CORE"
cpu_architecture = "X86_64" # or "ARM64"
}
AWS CLI Session Manager plugin
https://docs.aws.amazon.com/systems-manager/latest/userguide/install-plugin-debian-and-ubuntu.html
curl -o "session-manager-plugin.deb" "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/ubuntu_64bit/session-manager-plugin.deb"
sudo dpkg -i session-manager-plugin.deb
(for uninstalling) sudo dpkg -r session-manager-plugin
Verify installation
session-manager-plugin
Interactive shell:
aws ecs execute-command \
--cluster myapp-dev-ecs-cluster \
--task 497e158aeb3243288a36b4fba3dfd2c2 \
--container myapp_back \
--command "/bin/sh" \
--interactive
Find out the public IP:
wget -qO- icanhazip.com
55.176.247.88
Test connectivity to host and port
nc -zv sso.myapp.org 443
modules/ecs/ecs.tf
resource "aws_ecs_cluster" "cluster" {
name = var.ecs_cluster_name
setting {
name = "containerInsights" #CloudWatch Container Insights
value = "disabled" #{enhanced, enabled, disabled} Additional charges
}
}
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
}
}
resource "aws_ecs_service" "service" {
//DOC. make sure to set depends_on to the related aws_iam_role_policy
depends_on = [aws_ecs_task_definition.task_definition]
lifecycle {
ignore_changes = [
desired_count,
task_definition,
]
}
name = var.name_ecs_service
cluster = aws_ecs_cluster.cluster.id
deployment_circuit_breaker {
enable = true
rollback = true
}
task_definition = "${aws_ecs_task_definition.task_definition.family}:${aws_ecs_task_definition.task_definition.revision}"
desired_count = var.task_desire_count
enable_execute_command = true #(Optional) Whether to enable Amazon ECS Exec for the tasks within the service
# launch_type = "FARGATE"
load_balancer { #Use multiple load_balancer blocks for multiple LB target groups
target_group_arn = var.lb_target_group_external_arn
container_name = var.container_name
container_port = 8080
}
load_balancer {
target_group_arn = var.lb_target_group_internal_arn
container_name = var.container_name
container_port = 8080
}
network_configuration {
security_groups = [aws_security_group.sg_ecs.id]
subnets = var.subnets_ids
}
capacity_provider_strategy {
capacity_provider = "FARGATE"
weight = "1"
base = "1"
}
capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
weight = "2"
}
tags = {
Name = var.name_ecs_service,
Schedule = var.schedule
}
}