Skip to content

Commit

Permalink
Service 2: backend-fargate-svc (aws-samples#15)
Browse files Browse the repository at this point in the history
Adding backend-fargate-svc.
  • Loading branch information
mikewrighton authored Apr 29, 2022
1 parent e8e0c0a commit 9fcb061
Show file tree
Hide file tree
Showing 14 changed files with 1,120 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"service": {
"name": "backend-fargate-svc",
"inputs": {
},
"repository_connection_arn": "REPLACE_ME",
"repository_id": "REPLACE_ME",
"branch_name": "REPLACE_ME"
},
"service_instances": [
{
"name": "instance1",
"inputs": {
},
"outputs": {
"LambdaRuntime": "nodejs12.x"
},
"environment": {
"account_id": "",
"name": "",
"outputs": {}
}
}
],
"pipeline": {
"inputs": {
"service_dir": "ecs-backend",
"environment_account_ids": "",
"unit_test_command": "echo 'add your unit test command here'",
"dockerfile": "Dockerfile"
}
},
"environment": {
"outputs": {
"ServiceTaskDefExecutionRoleArn" : "REPLACE_ME",
"CloudMapNamespaceId": "REPLACE_ME",
"VpcId": "REPLACE_ME",
"SnsTopicArn": "REPLACE_ME",
"SnsTopicName": "REPLACE_ME",
"ClusterName": "REPLACE_ME",
"PrivateSubnetOneId": "REPLACE_ME",
"PrivateSubnetTwoId": "REPLACE_ME",
"PublicSubnetOneId": "REPLACE_ME",
"PublicSubnetTwoId": "REPLACE_ME"
}
},
"service_instance": {
"name": "instance1",
"inputs": {
"port": "80",
"image": "public.ecr.aws/z9d2n7e1/nginx:1.21.0",
"task_size": "x-small",
"desired_count": "1",
"subnet_type": "public"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@

variable "service_instances" {
type = list(
object({
name = string
inputs = map(string)
outputs = map(string)
environment = object({
account_id = string
name = string
outputs = map(string)
})
})
)
}

variable "service_instance" {
type = object({
name = string
inputs = map(string)
})
default = null
}

variable "service" {
type = object({
name = string
repository_id = string
repository_connection_arn = string
branch_name = string
})
default = null
}

variable "environment" {
type = object({
outputs = map(string)
})
default = null
}

variable "pipeline" {
type = object({
inputs = map(string)
})
default = null
}
1 change: 1 addition & 0 deletions service-templates/backend-fargate-svc/v1/.compatible-envs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fargate-env:1
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}

backend "s3" {}
}

# Configure the AWS Provider
provider "aws" {
region = var.aws_region
alias = "default"

default_tags {
tags = {
"proton:service" = var.service.name
}
}
}

variable "aws_region" {
type = string
default = "us-east-1"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
data "aws_region" "current" {}

data "aws_caller_identity" "current" {}

data "aws_partition" "current" {}

data "aws_iam_policy_document" "sns_publish_policy_document" {
statement {
actions = [
"sns:Publish"
]
resources = [
var.environment.outputs.SnsTopicArn
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
resource "aws_iam_role" "service_task_def_role" {
assume_role_policy = jsonencode({
"Version" : "2012-10-17",
"Statement" : [
{
"Effect" : "Allow",
"Principal" : {
"Service" : "ecs-tasks.amazonaws.com"
},
"Action" : "sts:AssumeRole"
}
]
})
}

resource "aws_iam_role_policy_attachment" "ssn_publish_policy" {
role = aws_iam_role.service_task_def_role.name
policy_arn = aws_iam_policy.sns_publish_policy.arn
}

resource "aws_iam_policy" "sns_publish_policy" {
policy = data.aws_iam_policy_document.sns_publish_policy_document.json
}

variable "task_sizes" {
default = {
x-small = { cpu = 256, memory = 512 }
small = { cpu = 512, memory = 1024 }
medium = { cpu = 1024, memory = 2048 }
large = { cpu = 2048, memory = 4096 }
x-large = { cpu = 4096, memory = 8192 }
}
}

resource "aws_ecs_task_definition" "service_task_def" {
container_definitions = jsonencode([
{
essential = true,
image = var.service_instance.inputs.image,
logConfiguration = {
logDriver = "awslogs",
options = {
awslogs-group : aws_cloudwatch_log_group.service_log_group.name,
awslogs-region : var.aws_region,
awslogs-stream-prefix : "${var.service.name}/${var.service_instance.name}"
}
},
name = var.service_instance.name,
portMappings = [
{
containerPort = tonumber(var.service_instance.inputs.port)
protocol = "tcp"
}
],
environment = [
{ name = "SNS_TOPIC_ARN", value = "{'ping':'${var.environment.outputs.SnsTopicArn}'}" },
{ name = "SNS_REGION", value = var.aws_region }
],
}
])
cpu = lookup(var.task_sizes[var.service_instance.inputs.task_size], "cpu")
execution_role_arn = var.environment.outputs.ServiceTaskDefExecutionRoleArn
family = "${var.service.name}_${var.service_instance.name}"
memory = lookup(var.task_sizes[var.service_instance.inputs.task_size], "memory")
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
task_role_arn = aws_iam_role.service_task_def_role.arn
}

resource "aws_cloudwatch_log_group" "service_log_group" {
}

resource "aws_ecs_service" "service" {
cluster = var.environment.outputs.ClusterName
name = "${var.service.name}_${var.service_instance.name}"
deployment_maximum_percent = 200
deployment_minimum_healthy_percent = 50
desired_count = var.service_instance.inputs.desired_count
enable_ecs_managed_tags = false
launch_type = "FARGATE"
network_configuration {
assign_public_ip = var.service_instance.inputs.subnet_type == "private" ? false : true
security_groups = [aws_security_group.service_security_group.id]
subnets = var.service_instance.inputs.subnet_type == "private" ? [
var.environment.outputs.PrivateSubnetOneId, var.environment.outputs.PrivateSubnetTwoId
] : [
var.environment.outputs.PublicSubnetOneId, var.environment.outputs.PublicSubnetTwoId
]
}

service_registries {
registry_arn = aws_service_discovery_service.cloudmap_service.arn
}
task_definition = aws_ecs_task_definition.service_task_def.arn
}

resource "aws_service_discovery_service" "cloudmap_service" {
dns_config {
dns_records {
ttl = 60
type = "A"
}
namespace_id = var.environment.outputs.CloudMapNamespaceId
routing_policy = "MULTIVALUE"
}
health_check_custom_config {
failure_threshold = 1
}
name = "${var.service.name}.${var.service_instance.name}"
namespace_id = var.environment.outputs.CloudMapNamespaceId
}

resource "aws_security_group" "service_security_group" {
description = "Automatically created Security Group for the Service"

ingress {
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all inbound traffic by default"
protocol = "-1"
to_port = 0
from_port = 0
}

egress {
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound traffic by default"
protocol = "-1"
to_port = 0
from_port = 0
}
vpc_id = var.environment.outputs.VpcId
}

resource "aws_appautoscaling_target" "service_task_count_target" {
depends_on = [aws_ecs_service.service]
max_capacity = 10
min_capacity = 1
resource_id = "service/${var.environment.outputs.ClusterName}/${aws_ecs_service.service.name}"
role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/aws-service-role/ecs.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_ECSService"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}

resource "aws_appautoscaling_policy" "service_task_count_target_cpu_scaling" {
name = "${aws_ecs_service.service.name}_BackendFargateServiceTaskCountTargetCpuScaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.service_task_count_target.resource_id
scalable_dimension = aws_appautoscaling_target.service_task_count_target.scalable_dimension
service_namespace = aws_appautoscaling_target.service_task_count_target.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 50
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
}
}

resource "aws_appautoscaling_policy" "service_task_count_target_memory_scaling" {
name = "${aws_ecs_service.service.name}_BackendFargateServiceTaskCountTargetMemoryScaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.service_task_count_target.resource_id
scalable_dimension = aws_appautoscaling_target.service_task_count_target.scalable_dimension
service_namespace = aws_appautoscaling_target.service_task_count_target.service_namespace
target_tracking_scaling_policy_configuration {
target_value = 50
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageMemoryUtilization"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
infrastructure:
templates:
- file: "*"
rendering_engine: hcl
template_language: terraform
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}

backend "s3" {}
}

# Configure the AWS Provider
provider "aws" {
region = var.aws_region
alias = "default"

default_tags {
tags = {
"proton:pipeline" = var.service.name
}
}
}

variable "aws_region" {
type = string
default = "us-east-1"
}
Loading

0 comments on commit 9fcb061

Please sign in to comment.