Skip to content

Commit

Permalink
infra: ECS cluster, service, task, and related infrastructure (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
michalc authored Feb 22, 2025
1 parent 77ea8fa commit e6420d5
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 1 deletion.
14 changes: 14 additions & 0 deletions infra/1-variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,17 @@ variable "subnets_private" {
},
]
}

variable "container_port" {
type = number
default = 8000
}

variable "container_name" {
type = string
default = "main"
}

variable "domain_name" {
type = string
}
1 change: 0 additions & 1 deletion infra/2-common.tf

This file was deleted.

5 changes: 5 additions & 0 deletions infra/2-data.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
data "aws_region" "current" {}

data "aws_ec2_managed_prefix_list" "cloudfront" {
name = "com.amazonaws.global.cloudfront.origin-facing"
}
8 changes: 8 additions & 0 deletions infra/4-acm.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "aws_acm_certificate" "main" {
domain_name = var.domain_name
validation_method = "DNS"
}

resource "aws_acm_certificate_validation" "main" {
certificate_arn = aws_acm_certificate.main.arn
}
File renamed without changes.
164 changes: 164 additions & 0 deletions infra/6-ecs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
resource "aws_ecs_cluster" "main" {
name = "${var.prefix}-${var.suffix}"
}

resource "aws_ecs_service" "main" {
name = "${var.prefix}-${var.suffix}"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.main.arn
launch_type = "FARGATE"
desired_count = 1

load_balancer {
target_group_arn = aws_lb_target_group.main.arn
container_name = var.container_name
container_port = var.container_port
}

network_configuration {
subnets = aws_subnet.private[*].id
security_groups = [aws_security_group.ecs_service.id]
}
}

resource "aws_ecs_task_definition" "main" {
family = "${var.prefix}-${var.suffix}"
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 1024
memory = 3072
execution_role_arn = aws_iam_role.ecs_task_main_execution.arn
container_definitions = jsonencode([
{
name = var.container_name
image = "${aws_ecr_repository.main.repository_url}:latest"
essential = true
portMappings = [
{
containerPort = var.container_port
hostPort = var.container_port
}
],
logConfiguration = {
logDriver = "awslogs"
options = {
awslogs-group = aws_cloudwatch_log_group.ecs_task.name
awslogs-region = data.aws_region.current.name
awslogs-stream-prefix = var.container_name
}
}
}
])
}

resource "aws_cloudwatch_log_group" "ecs_task" {
name = "${var.prefix}-ecs-task-${var.suffix}"
retention_in_days = "3653"
}

resource "aws_iam_role" "ecs_task_main_execution" {
name = "${var.prefix}-task-execution-${var.suffix}"

assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "ecs-tasks.amazonaws.com"
}
},
]
})
}

resource "aws_iam_role_policy_attachment" "ecs_task_main_execution" {
role = aws_iam_role.ecs_task_main_execution.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

resource "aws_lb" "main" {
name = "${var.prefix}-${var.suffix}"
subnets = aws_subnet.public.*.id
security_groups = ["${aws_security_group.lb.id}"]
}

resource "aws_security_group" "lb" {
name = "${var.prefix}-${var.suffix}"
description = "${var.prefix}-${var.suffix}"
vpc_id = aws_vpc.main.id

tags = {
Name = "${var.prefix}-${var.suffix}"
}
}

resource "aws_vpc_security_group_ingress_rule" "ecs_service_from_cloudwatch" {
security_group_id = aws_security_group.lb.id
prefix_list_id = data.aws_ec2_managed_prefix_list.cloudfront.id

ip_protocol = "tcp"
from_port = "443"
to_port = "443"
}

resource "aws_security_group" "ecs_service" {
name = "${var.prefix}-ecs-service-${var.suffix}"
description = "${var.prefix}-ecs-service-${var.suffix}"
vpc_id = aws_vpc.main.id

tags = {
Name = "${var.prefix}-ecs-service-${var.suffix}"
}
}

resource "aws_vpc_security_group_egress_rule" "lb_to_ecs_service" {
security_group_id = aws_security_group.lb.id
referenced_security_group_id = aws_security_group.ecs_service.id

ip_protocol = "tcp"
from_port = var.container_port
to_port = var.container_port
}

resource "aws_vpc_security_group_ingress_rule" "ecs_service_from_lb" {
security_group_id = aws_security_group.ecs_service.id
referenced_security_group_id = aws_security_group.lb.id

ip_protocol = "tcp"
from_port = var.container_port
to_port = var.container_port
}

# Should be tighter - only needed to pull images from ECR
resource "aws_vpc_security_group_egress_rule" "ecs_service_https_to_all" {
security_group_id = aws_security_group.ecs_service.id
cidr_ipv4 = "0.0.0.0/0"

ip_protocol = "tcp"
from_port = "443"
to_port = "443"
}

resource "aws_lb_listener" "main" {
load_balancer_arn = aws_lb.main.arn
port = "443"
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
certificate_arn = aws_acm_certificate.main.arn

default_action {
type = "forward"
target_group_arn = aws_lb_target_group.main.arn
}
}

resource "aws_lb_target_group" "main" {
name = "${var.prefix}-${var.suffix}"
vpc_id = aws_vpc.main.id
port = var.container_port
protocol = "HTTP"
target_type = "ip"
}

0 comments on commit e6420d5

Please sign in to comment.