gabriel becker
1 year ago
17 changed files with 472 additions and 77 deletions
@ -1,3 +1,3 @@ |
|||||||
.terraform |
.terraform |
||||||
.terraform* |
.terraform* |
||||||
*.tfstate* |
*.tfstate |
||||||
|
@ -0,0 +1,40 @@ |
|||||||
|
resource "aws_lb_target_group" "api_lb_target" { |
||||||
|
name = "my-api" |
||||||
|
port = 3000 |
||||||
|
protocol = "HTTP" |
||||||
|
target_type = "ip" |
||||||
|
vpc_id = aws_vpc.app_vpc.id |
||||||
|
health_check { |
||||||
|
enabled = true |
||||||
|
path = "/health" |
||||||
|
} |
||||||
|
depends_on = [aws_alb.api_lb] |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_alb" "api_lb" { |
||||||
|
name = "${var.project}-api-lb" |
||||||
|
internal = false |
||||||
|
load_balancer_type = "application" |
||||||
|
subnets = [for s in aws_subnet.public_subnet : s.id] |
||||||
|
security_groups = [ |
||||||
|
aws_security_group.http.id, |
||||||
|
aws_security_group.https.id, |
||||||
|
aws_security_group.egress_all.id, |
||||||
|
aws_security_group.ingress_api.id, |
||||||
|
] |
||||||
|
depends_on = [aws_internet_gateway.igw] |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_alb_listener" "api_http_listener" { |
||||||
|
load_balancer_arn = aws_alb.api_lb.arn |
||||||
|
port = "80" |
||||||
|
protocol = "HTTP" |
||||||
|
default_action { |
||||||
|
type = "forward" |
||||||
|
target_group_arn = aws_lb_target_group.api_lb_target.arn |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
output "alb_url" { |
||||||
|
value = "http://${aws_alb.api_lb.dns_name}" |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
locals { |
||||||
|
api_name = "${var.project}-api" |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_ecs_cluster" "my_cluster" { |
||||||
|
name = "my_cluster" |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_ecs_service" "api_ecs" { |
||||||
|
name = local.api_name |
||||||
|
task_definition = aws_ecs_task_definition.api_task.arn |
||||||
|
cluster = aws_ecs_cluster.my_cluster.id |
||||||
|
launch_type = "FARGATE" |
||||||
|
load_balancer { |
||||||
|
target_group_arn = aws_lb_target_group.api_lb_target.arn |
||||||
|
container_name = local.api_name |
||||||
|
container_port = "3000" |
||||||
|
} |
||||||
|
desired_count = 1 |
||||||
|
network_configuration { |
||||||
|
assign_public_ip = false |
||||||
|
security_groups = [ |
||||||
|
aws_security_group.egress_all.id, |
||||||
|
aws_security_group.ingress_api.id, |
||||||
|
] |
||||||
|
subnets = [for s in aws_subnet.private_subnet : s.id] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_ecs_task_definition" "api_task" { |
||||||
|
family = local.api_name |
||||||
|
execution_role_arn = aws_iam_role.api_exec_role.arn |
||||||
|
cpu = 256 |
||||||
|
memory = 512 |
||||||
|
requires_compatibilities = ["FARGATE"] |
||||||
|
network_mode = "awsvpc" |
||||||
|
|
||||||
|
container_definitions = jsonencode([ |
||||||
|
{ |
||||||
|
name = local.api_name, |
||||||
|
image = var.container_image, |
||||||
|
portMappings = [ |
||||||
|
{ |
||||||
|
containerPort = 3000 |
||||||
|
} |
||||||
|
], |
||||||
|
logConfiguration = { |
||||||
|
logDriver = "awslogs", |
||||||
|
options = { |
||||||
|
awslogs-region = var.region, |
||||||
|
awslogs-group = "/ecs/${local.api_name}", |
||||||
|
awslogs-stream-prefix = "ecs" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
]) |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "log_group" { |
||||||
|
name = "/ecs/${local.api_name}" |
||||||
|
} |
@ -1,39 +0,0 @@ |
|||||||
resource "aws_ecs_service" "api_ecs" { |
|
||||||
name = "${var.project}-api" |
|
||||||
task_definition = aws_ecs_task_definition.api_task.arn |
|
||||||
launch_type = "FARGATE" |
|
||||||
} |
|
||||||
|
|
||||||
resource "aws_ecs_task_definition" "api_task" { |
|
||||||
family = "${var.project}-api" |
|
||||||
cpu = 256 |
|
||||||
memory = 512 |
|
||||||
requires_compatibilities = ["FARGATE"] |
|
||||||
network_mode = "awsvpc" |
|
||||||
|
|
||||||
execution_role_arn = aws_iam_role.api_exec_role.arn |
|
||||||
|
|
||||||
container_definitions = jsonencode([ |
|
||||||
{ |
|
||||||
name = "${var.project}-api", |
|
||||||
image = var.container_image, |
|
||||||
portMappings = [ |
|
||||||
{ |
|
||||||
containerPort = 3000 |
|
||||||
} |
|
||||||
], |
|
||||||
logConfiguration = { |
|
||||||
logDriver = "awslogs", |
|
||||||
options = { |
|
||||||
awslogs-region = var.region, |
|
||||||
awslogs-group = "/ecs/${var.project}-api", |
|
||||||
awslogs-stream-prefix = "ecs" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
]) |
|
||||||
} |
|
||||||
|
|
||||||
resource "aws_cloudwatch_log_group" "log_group" { |
|
||||||
name = "/ecs/${var.project}-api" |
|
||||||
} |
|
@ -0,0 +1,4 @@ |
|||||||
|
# output "ecs-ip" { |
||||||
|
# description = "ecs-ip" |
||||||
|
# value = [for s in aws_eip.nat.map : s.public_ip] |
||||||
|
# } |
@ -0,0 +1,38 @@ |
|||||||
|
resource "aws_lb_target_group" "my_api" { |
||||||
|
name = "my-api" |
||||||
|
port = 3000 |
||||||
|
protocol = "HTTP" |
||||||
|
target_type = "ip" |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
health_check { |
||||||
|
enabled = true |
||||||
|
path = "/health" |
||||||
|
} |
||||||
|
depends_on = [aws_alb.my_api] |
||||||
|
} |
||||||
|
resource "aws_alb" "my_api" { |
||||||
|
name = "my-api-lb" |
||||||
|
internal = false |
||||||
|
load_balancer_type = "application" |
||||||
|
subnets = [ |
||||||
|
aws_subnet.public_a.id, |
||||||
|
aws_subnet.public_b.id |
||||||
|
] |
||||||
|
security_groups = [ |
||||||
|
aws_security_group.http.id, |
||||||
|
aws_security_group.egress_all.id, |
||||||
|
] |
||||||
|
depends_on = [aws_internet_gateway.igw] |
||||||
|
} |
||||||
|
resource "aws_alb_listener" "my_api_http" { |
||||||
|
load_balancer_arn = aws_alb.my_api.arn |
||||||
|
port = "80" |
||||||
|
protocol = "HTTP" |
||||||
|
default_action { |
||||||
|
type = "forward" |
||||||
|
target_group_arn = aws_lb_target_group.my_api.arn |
||||||
|
} |
||||||
|
} |
||||||
|
output "alb_url" { |
||||||
|
value = "http://${aws_alb.my_api.dns_name}" |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
terraform { |
||||||
|
required_providers { |
||||||
|
aws = { |
||||||
|
source = "hashicorp/aws" |
||||||
|
version = "~>4.0" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
provider "aws" { |
||||||
|
region = var.region |
||||||
|
profile = var.profile |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
resource "aws_ecs_cluster" "my_cluster" { |
||||||
|
name = "my_cluster" |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_ecs_task_definition" "my_api" { |
||||||
|
family = "my-api" |
||||||
|
execution_role_arn = aws_iam_role.my_api_task_execution_role.arn |
||||||
|
container_definitions = <<EOF |
||||||
|
[ |
||||||
|
{ |
||||||
|
"name": "my-api", |
||||||
|
"image": "mohitmutha/simplefastifyservice:1.0", |
||||||
|
"portMappings": [ |
||||||
|
{ |
||||||
|
"containerPort": 3000 |
||||||
|
} |
||||||
|
], |
||||||
|
"logConfiguration": { |
||||||
|
"logDriver": "awslogs", |
||||||
|
"options": { |
||||||
|
"awslogs-region": "ap-southeast-2", |
||||||
|
"awslogs-group": "/ecs/my-api", |
||||||
|
"awslogs-stream-prefix": "ecs" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
] |
||||||
|
EOF |
||||||
|
# These are the minimum values for Fargate containers. |
||||||
|
cpu = 256 |
||||||
|
memory = 512 |
||||||
|
requires_compatibilities = ["FARGATE"] |
||||||
|
network_mode = "awsvpc" |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_cloudwatch_log_group" "my_api" { |
||||||
|
name = "/ecs/my-api" |
||||||
|
} |
||||||
|
|
@ -0,0 +1,24 @@ |
|||||||
|
resource "aws_iam_role" "my_api_task_execution_role" { |
||||||
|
name = "my-api-task-execution-role" |
||||||
|
assume_role_policy = data.aws_iam_policy_document.ecs_task_assume_role.json |
||||||
|
} |
||||||
|
data "aws_iam_policy_document" "ecs_task_assume_role" { |
||||||
|
statement { |
||||||
|
actions = ["sts:AssumeRole"] |
||||||
|
principals { |
||||||
|
type = "Service" |
||||||
|
identifiers = ["ecs-tasks.amazonaws.com"] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
# Normally we'd prefer not to hardcode an ARN in our Terraform, but since this is |
||||||
|
# an AWS-managed policy, it's okay. |
||||||
|
data "aws_iam_policy" "ecs_task_execution_role" { |
||||||
|
arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" |
||||||
|
} |
||||||
|
# Attach the above policy to the execution role. |
||||||
|
resource "aws_iam_role_policy_attachment" "ecs_task_execution_role" { |
||||||
|
role = aws_iam_role.my_api_task_execution_role.name |
||||||
|
policy_arn = data.aws_iam_policy.ecs_task_execution_role.arn |
||||||
|
} |
||||||
|
|
@ -0,0 +1,132 @@ |
|||||||
|
resource "aws_vpc" "prod_vpc" { |
||||||
|
cidr_block = "10.0.0.0/16" |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
resource "aws_subnet" "public_a" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
cidr_block = "10.0.1.0/25" |
||||||
|
availability_zone = "ap-southeast-2a" |
||||||
|
tags = { |
||||||
|
"Name" = "public | ap-southeast-2a" |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_subnet" "public_b" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
cidr_block = "10.0.1.128/25" |
||||||
|
availability_zone = "ap-southeast-2b" |
||||||
|
tags = { |
||||||
|
"Name" = "public | ap-southeast-2b" |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_subnet" "private_a" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
cidr_block = "10.0.2.0/25" |
||||||
|
availability_zone = "ap-southeast-2a" |
||||||
|
tags = { |
||||||
|
"Name" = "private | ap-southeast-2a" |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_subnet" "private_b" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
cidr_block = "10.0.2.128/25" |
||||||
|
availability_zone = "ap-southeast-2b" |
||||||
|
tags = { |
||||||
|
"Name" = "private | ap-southeast-2b" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
resource "aws_route_table" "public" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
tags = { |
||||||
|
"Name" = "public" |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_route_table" "private" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
tags = { |
||||||
|
"Name" = "private" |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_route_table_association" "public_a_subnet" { |
||||||
|
subnet_id = aws_subnet.public_a.id |
||||||
|
route_table_id = aws_route_table.public.id |
||||||
|
} |
||||||
|
resource "aws_route_table_association" "private_a_subnet" { |
||||||
|
subnet_id = aws_subnet.private_b.id |
||||||
|
route_table_id = aws_route_table.private.id |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
resource "aws_eip" "nat" { |
||||||
|
} |
||||||
|
resource "aws_internet_gateway" "igw" { |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
} |
||||||
|
resource "aws_nat_gateway" "ngw" { |
||||||
|
subnet_id = aws_subnet.public_a.id |
||||||
|
allocation_id = aws_eip.nat.id |
||||||
|
depends_on = [aws_internet_gateway.igw] |
||||||
|
} |
||||||
|
|
||||||
|
resource "aws_route" "public_igw" { |
||||||
|
route_table_id = aws_route_table.public.id |
||||||
|
destination_cidr_block = "0.0.0.0/0" |
||||||
|
gateway_id = aws_internet_gateway.igw.id |
||||||
|
} |
||||||
|
resource "aws_route" "private_ngw" { |
||||||
|
route_table_id = aws_route_table.private.id |
||||||
|
destination_cidr_block = "0.0.0.0/0" |
||||||
|
nat_gateway_id = aws_nat_gateway.ngw.id |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
resource "aws_security_group" "http" { |
||||||
|
name = "http" |
||||||
|
description = "HTTP traffic" |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
ingress { |
||||||
|
from_port = 80 |
||||||
|
to_port = 80 |
||||||
|
protocol = "TCP" |
||||||
|
cidr_blocks = ["0.0.0.0/0"] |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_security_group" "https" { |
||||||
|
name = "https" |
||||||
|
description = "HTTPS traffic" |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
ingress { |
||||||
|
from_port = 443 |
||||||
|
to_port = 443 |
||||||
|
protocol = "TCP" |
||||||
|
cidr_blocks = ["0.0.0.0/0"] |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_security_group" "egress_all" { |
||||||
|
name = "egress-all" |
||||||
|
description = "Allow all outbound traffic" |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
egress { |
||||||
|
from_port = 0 |
||||||
|
to_port = 0 |
||||||
|
protocol = "-1" |
||||||
|
cidr_blocks = ["0.0.0.0/0"] |
||||||
|
} |
||||||
|
} |
||||||
|
resource "aws_security_group" "ingress_api" { |
||||||
|
name = "ingress-api" |
||||||
|
description = "Allow ingress to API" |
||||||
|
vpc_id = aws_vpc.prod_vpc.id |
||||||
|
ingress { |
||||||
|
from_port = 3000 |
||||||
|
to_port = 3000 |
||||||
|
protocol = "TCP" |
||||||
|
cidr_blocks = ["0.0.0.0/0"] |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,23 @@ |
|||||||
|
resource "aws_ecs_service" "my_api" { |
||||||
|
name = "my-api" |
||||||
|
task_definition = aws_ecs_task_definition.my_api.arn |
||||||
|
cluster = aws_ecs_cluster.my_cluster.id |
||||||
|
launch_type = "FARGATE" |
||||||
|
load_balancer { |
||||||
|
target_group_arn = aws_lb_target_group.my_api.arn |
||||||
|
container_name = "my-api" |
||||||
|
container_port = "3000" |
||||||
|
} |
||||||
|
desired_count = 1 |
||||||
|
network_configuration { |
||||||
|
assign_public_ip = false |
||||||
|
security_groups = [ |
||||||
|
aws_security_group.egress_all.id, |
||||||
|
aws_security_group.ingress_api.id, |
||||||
|
] |
||||||
|
subnets = [ |
||||||
|
aws_subnet.private_a.id, |
||||||
|
aws_subnet.private_b.id |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
variable "region" { |
||||||
|
default = "ap-southeast-2" |
||||||
|
} |
||||||
|
|
||||||
|
variable "profile" { |
||||||
|
default = "superuser" |
||||||
|
} |
||||||
|
|
||||||
|
variable "project" { |
||||||
|
default = "template" |
||||||
|
} |
||||||
|
|
||||||
|
variable "container_image" { |
||||||
|
default = "ghcr.io/jimmysawczuk/sun-api:latest" |
||||||
|
} |
||||||
|
|
||||||
|
variable "zones" { |
||||||
|
type = set(string) |
||||||
|
default = [ |
||||||
|
"ap-southeast-2a", |
||||||
|
"ap-southeast-2b", |
||||||
|
"ap-southeast-2c", |
||||||
|
] |
||||||
|
} |
||||||
|
|
||||||
|
variable "public_subnets" { |
||||||
|
description = "Availability zone for instance associated with ip ranges" |
||||||
|
type = map(any) |
||||||
|
default = { |
||||||
|
"ap-southeast-2a" = "10.0.1.0/25" |
||||||
|
"ap-southeast-2b" = "10.0.2.0/25" |
||||||
|
"ap-southeast-2c" = "10.0.3.0/25" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
variable "private_subnets" { |
||||||
|
description = "Availability zone for instance associated with ip ranges" |
||||||
|
type = map(any) |
||||||
|
default = { |
||||||
|
"ap-southeast-2a" = "10.0.1.128/25" |
||||||
|
"ap-southeast-2b" = "10.0.2.128/25" |
||||||
|
"ap-southeast-2c" = "10.0.3.128/25" |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue