terraform-tofu-labs/demo/iac/ecs.tf
2024-04-15 21:41:32 +01:00

301 lines
6.9 KiB
HCL

################################################################################
# Cluster
################################################################################
module "ecs_cluster" {
source = "./modules/cluster"
cluster_name = local.name
# Capacity provider
fargate_capacity_providers = {
FARGATE = {
default_capacity_provider_strategy = {
weight = 50
base = 20
}
}
FARGATE_SPOT = {
default_capacity_provider_strategy = {
weight = 50
}
}
}
tags = local.tags
}
################################################################################
# Service
################################################################################
module "ecs_service" {
source = "./modules/service"
name = local.name
cluster_arn = module.ecs_cluster.arn
desired_count = 1
cpu = 1024
memory = 4096
# Enables ECS Exec
enable_execute_command = true
# Container definition(s)
container_definitions = {
(local.container_name) = {
cpu = 512
memory = 1024
image = "richarvey/chat-app:latest"
port_mappings = [
{
name = local.container_name
containerPort = local.container_port
hostPort = local.container_port
protocol = "tcp"
}
]
environment = [
{
name = "REDIS_ENDPOINT"
value = "valkey"
},
]
memory_reservation = 100
}
}
service_connect_configuration = {
namespace = aws_service_discovery_http_namespace.this.arn
service = {
client_alias = {
port = local.container_port
dns_name = local.container_name
}
port_name = local.container_name
discovery_name = local.container_name
}
}
load_balancer = {
service = {
target_group_arn = module.alb.target_groups["ex_ecs"].arn
container_name = local.container_name
container_port = local.container_port
}
}
subnet_ids = module.vpc.private_subnets
security_group_rules = {
alb_ingress_3000 = {
type = "ingress"
from_port = local.container_port
to_port = local.container_port
protocol = "tcp"
description = "Service port"
source_security_group_id = module.alb.security_group_id
}
egress_all = {
type = "egress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
service_tags = {
"ServiceTag" = "Tag on service level"
}
tags = local.tags
}
resource "aws_ecs_task_definition" "task" {
family = "service"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE", "EC2"]
cpu = 512
memory = 1024
container_definitions = jsonencode([
{
name = "valkey"
image = "valkey/valkey:7.2.4-rc1-alpine"
cpu = 512
memory = 1024
essential = true # if true and if fails, all other containers fail. Must have at least one essential
portMappings = [
{
name = "valkey"
containerPort = 6379
hostPort = 6379
}
]
}
])
}
resource "aws_ecs_service" "service" {
name = "valkey"
cluster = module.ecs_cluster.id
task_definition = aws_ecs_task_definition.task.id
desired_count = 1
launch_type = "FARGATE"
platform_version = "LATEST"
network_configuration {
assign_public_ip = false
security_groups = [aws_security_group.sg.id]
subnets = module.vpc.private_subnets
}
lifecycle {
ignore_changes = [task_definition]
}
service_connect_configuration {
enabled = true
namespace = "chat-app-demo"
service {
discovery_name = "valkey"
port_name = "valkey"
client_alias {
dns_name = "valkey"
port = 6379
}
}
}
}
resource "aws_security_group" "sg" {
name = "ecs"
vpc_id = module.vpc.vpc_id
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
protocol = -1
self = true
from_port = 0
to_port = 0
description = ""
}
ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
self = "false"
cidr_blocks = ["0.0.0.0/0"]
description = "Port 80"
}
}
resource "null_resource" "update_desired_count" {
triggers = {
# Changes to this value will trigger the API call execution below
desired_count = 3
}
provisioner "local-exec" {
interpreter = ["/bin/bash", "-c"]
# Note: this requires the awscli to be installed locally where Terraform is executed
command = <<-EOT
aws ecs update-service \
--cluster ${module.ecs_cluster.name} \
--service ${module.ecs_service.name} \
--desired-count ${null_resource.update_desired_count.triggers.desired_count}
EOT
}
}
################################################################################
# Supporting Resources
################################################################################
resource "aws_service_discovery_http_namespace" "this" {
name = local.name
description = "CloudMap namespace for ${local.name}"
tags = local.tags
}
module "alb" {
source = "terraform-aws-modules/alb/aws"
version = "~> 9.0"
name = local.name
load_balancer_type = "application"
vpc_id = module.vpc.vpc_id
subnets = module.vpc.public_subnets
# For example only
enable_deletion_protection = false
# Security Group
security_group_ingress_rules = {
all_http = {
from_port = 80
to_port = 80
ip_protocol = "tcp"
cidr_ipv4 = "0.0.0.0/0"
}
}
security_group_egress_rules = {
all = {
ip_protocol = "-1"
cidr_ipv4 = module.vpc.vpc_cidr_block
}
}
listeners = {
ex_http = {
port = 80
protocol = "HTTP"
forward = {
target_group_key = "ex_ecs"
}
}
}
target_groups = {
ex_ecs = {
backend_protocol = "HTTP"
backend_port = local.container_port
target_type = "ip"
deregistration_delay = 5
load_balancing_cross_zone_enabled = true
health_check = {
enabled = true
healthy_threshold = 5
interval = 30
matcher = "200"
path = "/"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 2
}
# There's nothing to attach here in this definition. Instead,
# ECS will attach the IPs of the tasks to this target group
create_attachment = false
}
}
tags = local.tags
}