diff --git a/autoscaling.tf b/autoscaling.tf index 17f3708..4fd4ed8 100644 --- a/autoscaling.tf +++ b/autoscaling.tf @@ -1,19 +1,19 @@ resource "aws_appautoscaling_target" "ecs_target" { - count = local.cluster_count + for_each = var.services max_capacity = 2 min_capacity = 1 - resource_id = "service/${aws_ecs_cluster.cluster_iac[0].name}/${aws_ecs_service.service_cluster[0].name}" + resource_id = "service/${local.cluster_name}/${aws_ecs_service.service_cluster[each.key].name}" scalable_dimension = "ecs:service:DesiredCount" service_namespace = "ecs" } resource "aws_appautoscaling_policy" "memory" { - count = local.cluster_count + for_each = var.services name = "memory" policy_type = "TargetTrackingScaling" - resource_id = aws_appautoscaling_target.ecs_target[0].resource_id - scalable_dimension = aws_appautoscaling_target.ecs_target[0].scalable_dimension - service_namespace = aws_appautoscaling_target.ecs_target[0].service_namespace + resource_id = aws_appautoscaling_target.ecs_target[each.key].resource_id + scalable_dimension = aws_appautoscaling_target.ecs_target[each.key].scalable_dimension + service_namespace = aws_appautoscaling_target.ecs_target[each.key].service_namespace target_tracking_scaling_policy_configuration { predefined_metric_specification { @@ -25,12 +25,12 @@ resource "aws_appautoscaling_policy" "memory" { } resource "aws_appautoscaling_policy" "cpu" { - count = local.cluster_count + for_each = var.services name = "cpu" policy_type = "TargetTrackingScaling" - resource_id = aws_appautoscaling_target.ecs_target[0].resource_id - scalable_dimension = aws_appautoscaling_target.ecs_target[0].scalable_dimension - service_namespace = aws_appautoscaling_target.ecs_target[0].service_namespace + resource_id = aws_appautoscaling_target.ecs_target[each.key].resource_id + scalable_dimension = aws_appautoscaling_target.ecs_target[each.key].scalable_dimension + service_namespace = aws_appautoscaling_target.ecs_target[each.key].service_namespace target_tracking_scaling_policy_configuration { predefined_metric_specification { diff --git a/cloudwatch.tf b/cloudwatch.tf index dd0f3de..72cda8d 100644 --- a/cloudwatch.tf +++ b/cloudwatch.tf @@ -1,5 +1,6 @@ resource "aws_cloudwatch_log_group" "main" { - name = "${var.service_name}-log" + for_each = var.services + name = "${each.value.name}-log" retention_in_days = "7" kms_key_id = null #tfsec:ignore:AWS089 diff --git a/how-to-use-this-module/container_definitions.json b/how-to-use-this-module/container_definitions.json deleted file mode 100644 index 33e9f8f..0000000 --- a/how-to-use-this-module/container_definitions.json +++ /dev/null @@ -1,29 +0,0 @@ -[ - { - "cpu": 256, - "image": "chnacib/mariaquiteria:latest", - "memory": 512, - "name": "api", - "networkMode": "awsvpc", - "portMappings": [ - { - "containerPort": 8000, - "hostPort": 8000 - } - ], - "environment": [ - { - "name": "AWESOME_ENV_VAR", - "value": "/mariaquiteria/aws_s3_region" - } - ], - "logConfiguration": { - "logDriver": "awslogs", - "options": { - "awslogs-group": "mentoria-log", - "awslogs-region": "us-east-1", - "awslogs-stream-prefix": "myawesomeapp" - } - } - } - ] \ No newline at end of file diff --git a/how-to-use-this-module/terrafile.tf b/how-to-use-this-module/terrafile.tf index 5929eba..5c314e2 100644 --- a/how-to-use-this-module/terrafile.tf +++ b/how-to-use-this-module/terrafile.tf @@ -3,26 +3,54 @@ provider "aws" { region = "us-east-1" } -data "template_file" "container_definitions" { - template = file("./container_definitions.json") +variable "vpc_id" { + type = string + default = "vpc-0645e6d450ce1bc30" } -module "ecs_mentoria" { - source = "../" - create_cluster = true - app_count = 1 - fargate_cpu = 256 - fargate_memory = 512 - subnet_ids = ["subnet-08e28abe0bb8c94cc", "subnet-0f22a250f019b5e1d"] - vpc_id = "vpc-0bf0d67ed0acdbd2a" - protocol = "HTTP" - family_name = "mentoria" - service_name = "mentoria" - cluster_name = "mentoria" - container1_name = "api" - container1_port = 8000 - container_definitions = data.template_file.container_definitions.rendered +data "aws_subnets" "main" { + filter { + name = "vpc-id" + values = [var.vpc_id] + } +} +module "ecs_mentoria" { + source = "../" + create_cluster = true + app_count = 1 + subnet_ids = data.aws_subnets.main.ids + vpc_id = var.vpc_id + cluster_name = "mentoria" + container1_name = "api" + container1_port = 8000 + services = { + "service1" = { + name = "service-test" + image = "nginx:latest" + cpu = "256" + memory = "512" + essential = true + environment_variables = [] + port_mappings = [{ + hostPort = 80 + containerPort = 80 + protocol = "TCP" + } + ] + health_check = { + command = [ + "CMD-SHELL", + "curl -f http://localhost:80/ || exit 1" + ] + retries = 3 + timeout = 5 + interval = 15 + startPeriod = 30 + } + expose = true + } + } tags = { Env = "production" Team = "tematico-terraform" @@ -32,6 +60,8 @@ module "ecs_mentoria" { } } + + output "load_balancer_dns_name" { value = "http://${module.ecs_mentoria.loadbalance_dns_name}" } diff --git a/loadbalance.tf b/loadbalance.tf index 10da6f0..198e683 100644 --- a/loadbalance.tf +++ b/loadbalance.tf @@ -12,22 +12,24 @@ resource "aws_lb" "iac_lb" { } resource "aws_lb_target_group" "iac_tg" { - name = "target-group-${var.cluster_name}" - port = var.container1_port - protocol = var.protocol + for_each = var.services + name = "target-group-${each.value.name}" + port = element(each.value.port_mappings.*.containerPort, 0) + protocol = element(each.value.port_mappings.*.protocol, 0) vpc_id = var.vpc_id target_type = "ip" } resource "aws_lb_listener" "iac_listener" { + for_each = var.services load_balancer_arn = aws_lb.iac_lb.arn - port = 80 - protocol = var.protocol #tfsec:ignore:AWS004 + port = element(each.value.port_mappings.*.containerPort, 0) + protocol = element(each.value.port_mappings.*.protocol, 0) #tfsec:ignore:AWS004 ssl_policy = var.policy_ssl certificate_arn = var.certificate_arn default_action { type = "forward" - target_group_arn = aws_lb_target_group.iac_tg.arn + target_group_arn = aws_lb_target_group.iac_tg[each.key].arn } } diff --git a/local.tf b/local.tf index 16ec69b..fae5c07 100644 --- a/local.tf +++ b/local.tf @@ -1,3 +1,4 @@ locals { cluster_count = var.create_cluster ? 1 : 0 + cluster_name = var.create_cluster ? aws_ecs_cluster.cluster_iac[0].name : var.cluster_name } diff --git a/service.tf b/service.tf index d840e9c..8f087d9 100644 --- a/service.tf +++ b/service.tf @@ -1,8 +1,8 @@ resource "aws_ecs_service" "service_cluster" { - count = local.cluster_count - name = var.service_name - cluster = aws_ecs_cluster.cluster_iac[0].arn - task_definition = aws_ecs_task_definition.task_cluster.arn + for_each = var.services + name = each.value.name + cluster = try(element(aws_ecs_cluster.cluster_iac.*.arn, 0), data.aws_ecs_cluster.main[0]) + task_definition = aws_ecs_task_definition.task_cluster[each.key].arn launch_type = "FARGATE" desired_count = var.app_count @@ -13,9 +13,9 @@ resource "aws_ecs_service" "service_cluster" { } load_balancer { - target_group_arn = aws_lb_target_group.iac_tg.id - container_name = var.container1_name - container_port = var.container1_port + target_group_arn = aws_lb_target_group.iac_tg[each.key].id + container_name = each.value.name + container_port = element(each.value.port_mappings.*.containerPort, 0) } tags = var.tags diff --git a/sg.tf b/sg.tf index dde4847..a634526 100644 --- a/sg.tf +++ b/sg.tf @@ -1,14 +1,19 @@ + resource "aws_security_group" "allow_access" { vpc_id = var.vpc_id - name = "${var.service_name}-sg" - description = "Permite acesso app ${var.family_name}" + name = "mentoria-sg" + description = "Permite acesso app mentoria" - ingress { - description = "allow app port" - from_port = 80 - to_port = var.container1_port - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] #tfsec:ignore:AWS008 + dynamic "ingress" { + for_each = var.services + content { + description = "allow app port" + from_port = element(ingress.value.port_mappings.*.containerPort, 0) + to_port = element(ingress.value.port_mappings.*.containerPort, 0) + protocol = "tcp" + self = ingress.value.expose == false + cidr_blocks = ingress.value.expose ? ["0.0.0.0/0"] : [] + } } egress { diff --git a/task-definition.tf b/task-definition.tf index 575c645..9d6668e 100644 --- a/task-definition.tf +++ b/task-definition.tf @@ -1,11 +1,34 @@ resource "aws_ecs_task_definition" "task_cluster" { - family = var.family_name + for_each = var.services + family = format("task-%s", each.value.name) requires_compatibilities = ["FARGATE"] - cpu = var.fargate_cpu - memory = var.fargate_memory + cpu = each.value.cpu + memory = each.value.memory network_mode = "awsvpc" task_role_arn = aws_iam_role.ecs_task_execution_role.arn - container_definitions = var.container_definitions + container_definitions = jsonencode( + [ + { + name = each.value.name + image = each.value.image + cpu = tonumber(each.value.cpu) + memory = tonumber(each.value.memory) + portMappings = each.value.port_mappings + essential = each.value.essential + environment = each.value.environment_variables + healthCheck = try(each.value.health_check, {}) + + logConfiguration = { + logDriver = "awslogs" + options = { + awslogs-region = "${var.region}" + awslogs-group = aws_cloudwatch_log_group.main[each.key].name + awslogs-stream-prefix = "service/${each.value.name}" + } + } + } + ] + ) execution_role_arn = aws_iam_role.ecs_task_execution_role.arn tags = var.tags diff --git a/variables.tf b/variables.tf index bc26830..0300067 100644 --- a/variables.tf +++ b/variables.tf @@ -21,32 +21,12 @@ variable "delete_protection" { description = "Impede que terraform exclua o load balance" } -variable "service_name" { - type = string - description = "Nome do service cluster que será criado" -} variable "app_count" { type = number description = "Números de tarefas em execução task definition" } - -variable "family_name" { - type = string - description = "Nome para task definition" -} - -variable "fargate_cpu" { - type = number - description = "Número de CPUs usados na taskde finition" -} - -variable "fargate_memory" { - type = number - description = "Quantidade de memória usada pela task definition" -} - variable "subnet_ids" { type = list(string) description = "Id da subnet" @@ -67,10 +47,6 @@ variable "container1_name" { description = "Nome do Container 1" } -variable "protocol" { - type = string - description = "Protocolo que será utilizado na aplicação " -} variable "policy_ssl" { type = string @@ -89,7 +65,94 @@ variable "tags" { description = "Tags para recursos" } -variable "container_definitions" { - type = string +variable "services" { + type = map( + object({ + name = string + image = string + cpu = optional(string, "256") # 1024 = 1vCPU units of vCPU + memory = optional(string, "512") # MB + port_mappings = list(object({ + hostPort = optional(number, 80) + containerPort = optional(number, 80) + protocol = optional(string, "TCP") + })) + essential = optional(bool, true) + environment_variables = optional(list(object({ + name = string + value = string + })), []) + + health_check = object({ + command = list(string) + retries = optional(number, 5) + timeout = optional(number, 10) + interval = optional(number, 5) + startPeriod = optional(number, 30) + } + ) + expose = optional(bool, false) + }) + ) + default = { + "service1" = { + name = "service-test" + image = "nginx:latest" + cpu = "256" + memory = "512" + essential = true + environment_variables = [] + port_mappings = [{ + hostPort = 80 + containerPort = 80 + protocol = "TCP" + }] + health_check = { + command = [ + "CMD-SHELL", + "curl -f http://localhost:80/ || exit 1" + ] + retries = 3 + timeout = 5 + interval = 15 + startPeriod = 30 + } + expose = true + }, + "service2" = { + name = "service-test2" + image = "nginx:latest" + cpu = "256" + memory = "512" + essential = true + environment_variables = [] + port_mappings = [{ + hostPort = 8080 + containerPort = 8080 + protocol = "TCP" + }] + health_check = { + command = [ + "CMD-SHELL", + "curl -f http://localhost:80/ || exit 1" + ] + retries = 3 + timeout = 5 + interval = 15 + startPeriod = 30 + } + } + } + description = "Arquivo de definição do service do ECS" + validation { + condition = alltrue([for k, v in var.services : tonumber(v.cpu) >= 256]) + error_message = "Todos os valores de CPU devem ser superiores a 256, pois o módulo utiliza Fargate." + } +} + +variable "region" { + type = string + description = "Região da AWS onde os recursos estão sendo aplicados" + default = "us-east-1" }