Grant permissions for ECS Task which is read from json file:
resource "aws_iam_role" "ecstask_role" {
name = "ecstask_role"
assume_role_policy = file("./templates/policies/ecstask_role.json")
}
resource "aws_iam_policy" "ecstask_policy" {
name = "ecstask_policy"
description = "Policy granting read/write access to ECR repositories"
policy = file("./templates/policies/ecstask_policy.json")
}
resource "aws_iam_role_policy_attachment" "ecr_policy_attachment" {
role = aws_iam_role.ecstask_role.name
policy_arn = aws_iam_policy.ecstask_policy.arn
}
Attach AmazonECSTaskExecutionRolePolicy
to allow ecs task running command inside container.
# IAM Policy for ECS Task can execute task
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role_policy" {
role = aws_iam_role.ecstask_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
Define all neccessary variables first:
locals {
# ECR repository URL with the 'latest' tag for the web application image
app_image = "${aws_ecr_repository.web_app_ecr.repository_url}:latest"
# Name for the container, incorporating the project name for uniqueness
container_name = "${local.project_name}-frontend"
# Port on which the containerized application listens (defined in the container image)
container_port = 80
# Host port on which the ECS service will expose the container (mapped to container_port)
host_port = 80
# Port for the Application Load Balancer in the production environment
product_port = 80
# Port for the Application Load Balancer in the pre-production environment
preproduct_port = 8088
# vCPU allocation for Fargate tasks, in CPU units (256 = 0.25 vCPU)
fargate_cpu = "256"
# Memory allocation for Fargate tasks, in MiB
fargate_memory = "512"
# Desired number of running tasks in the ECS service
desired_count = 1
# Health check path for the load balancer to verify container health
health_check_path = "/"
}
Render json template file with Terraform variables. This json file is used for container in Task Definition:
data "template_file" "container_template" {
template = file("./templates/ecs_container.json.tpl")
vars = {
container_name = local.container_name
app_image = local.app_image
container_port = local.container_port
host_port = local.host_port
fargate_cpu = local.fargate_cpu
fargate_memory = local.fargate_memory
aws_region = local.region
}
}
Creating ECS Cluster and ECS Task Definition:
resource "aws_ecs_cluster" "web_app_cluster" {
name = "${local.project_name}_cluster"
}
resource "aws_ecs_task_definition" "web_app_task" {
family = "${local.project_name}-task"
# ECS Task permission when deploying
task_role_arn = aws_iam_role.ecstask_role.arn
# Fargate permission when running
execution_role_arn = aws_iam_role.ecstask_role.arn
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = local.fargate_cpu
memory = local.fargate_memory
container_definitions = data.template_file.container_template.rendered
}
Export AWS-CLI stress test command:
--profile [your_IAM_user]
with your IAM user, created in this step Create IAM User:# List all running task ARNs
output "running_tasks" {
value = "aws ecs list-tasks --cluster ${aws_ecs_cluster.web_app_cluster.name} --region ${data.aws_region.current.id} --profile lab"
}
# Export the aws cli to test AutoScaling
output "stress_command" {
value= "aws ecs execute-command --cluster ${aws_ecs_cluster.web_app_cluster.name} --container ${local.container_name} --command 'stress-ng --cpu 0 --timeout 180s' --interactive --region ${data.aws_region.current.id} --profile lab --task [arn_running_task]"
}
ECS cluster runs on private subnet, so we have to setup ECS tasks that only allows inbound access from the ALB (Application Load Balancer) on the specified host port.
# Allow on ALB access to ECS cluster through port 80
resource "aws_security_group" "sg_ecs_tasks" {
name = "sg_ecs_tasks"
description = "Allow inbound access from the ALB only"
vpc_id = module.vpc.vpc_id
ingress {
protocol = "tcp"
from_port = local.host_port
to_port = local.host_port
security_groups = [aws_security_group.sg_alb.id]
description = "Allow access ECS Host port from only ALB"
}
egress {
protocol = "-1"
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}