Olá! Bem-vindo à nossa décima quinta lição.
Na aula anterior, você montou o "blueprint" da nossa aplicação .NET no ECS: criamos o repositório ECR para a imagem, definimos as permissões com uma IAM Role e, o mais importante, criamos a aws_ecs_task_definition. Agora temos o "onde" (o cluster ECS) e o "o quê" (a definição da tarefa), mas a nossa aplicação ainda não está em execução.
Nesta lição, vamos dar vida à nossa infraestrutura. Nosso objetivo é usar o Terraform para definir um Serviço ECS (aws_ecs_service) para executar e manter o número desejado de tarefas no Fargate. O serviço é o maestro da orquestra: ele pega a partitura (a Task Definition) e garante que os músicos (as tarefas) estejam tocando continuamente.
1. O Papel do Serviço ECS
Um serviço ECS é um recurso de longa duração que gerencia as tarefas dentro de um cluster. Suas principais responsabilidades são:
- Manter o estado desejado: Ele garante que um número especificado de instâncias de uma Task Definition (as "tarefas") esteja sempre em execução. Se uma tarefa falhar, o serviço a substitui automaticamente.
- Integração com Load Balancer: Ele pode registrar as tarefas em um Application Load Balancer (ALB) para distribuir o tráfego de entrada entre elas.
- Estratégias de deploy: Ele gerencia como as novas versões da sua aplicação são implantadas (por exemplo, rolling updates), minimizando o tempo de inatividade.
A imagem abaixo ilustra perfeitamente onde o serviço se encaixa. O tráfego do usuário chega a um ALB, que o encaminha para o ECS Service. O serviço, por sua vez, distribui esse tráfego entre as tarefas em execução que ele gerencia.

Para que o serviço funcione e seja acessível, precisamos de duas coisas: o próprio serviço e um meio de expô-lo à internet. Vamos começar configurando o ponto de entrada: o Application Load Balancer.
2. Expondo o Serviço: Application Load Balancer (ALB)
Um ALB distribui o tráfego de entrada para vários destinos, como tarefas ECS, em diferentes Zonas de Disponibilidade, aumentando a tolerância a falhas da sua aplicação.
Para configurar um ALB com Terraform, precisamos de três recursos principais:
aws_lb: O próprio load balancer.aws_lb_target_group: Um grupo de destino para onde o tráfego será roteado. Nossas tarefas ECS serão registradas aqui.aws_lb_listener: Um "ouvinte" no load balancer que verifica as solicitações de conexão (por exemplo, na porta 80 para HTTP) e as encaminha para um Target Group com base em regras.
Vamos criar um novo arquivo, alb.tf, para definir esses recursos.
// alb.tf
// 1. O próprio Application Load Balancer
resource "aws_lb" "app_lb" {
name = "my-dotnet-api-lb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.lb_sg.id]
subnets = module.vpc.public_subnets // Referencia as sub-redes públicas do módulo VPC
tags = {
Name = "my-dotnet-api-lb"
}
}
// 2. O Target Group para as tarefas ECS
resource "aws_lb_target_group" "app_tg" {
name = "my-dotnet-api-tg"
port = 80
protocol = "HTTP"
vpc_id = module.vpc.vpc_id // Referencia o VPC do módulo
target_type = "ip"
health_check {
path = "/healthz" // Endpoint de health check da sua API .NET
protocol = "HTTP"
matcher = "200"
interval = 30
timeout = 5
healthy_threshold = 2
unhealthy_threshold = 2
}
tags = {
Name = "my-dotnet-api-tg"
}
}
// 3. O Listener que conecta o LB ao Target Group
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.app_lb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.app_tg.arn
}
}
Observação: O código acima assume que você tem um módulo VPC chamado vpc (como fizemos em lições anteriores) e um endpoint de health check /healthz na sua API. A maioria dos templates de API .NET modernos inclui um endpoint de health check por padrão, muitas vezes em /health. Ajuste o path conforme necessário.
Também precisamos de grupos de segurança (security groups) para controlar o tráfego. Adicione um novo arquivo sg.tf:
// sg.tf
// Security Group para o Load Balancer
resource "aws_security_group" "lb_sg" {
name = "lb-sg"
description = "Allow HTTP traffic to the load balancer"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "lb-sg"
}
}
// Security Group para as tarefas ECS
resource "aws_security_group" "ecs_tasks_sg" {
name = "ecs-tasks-sg"
description = "Allow traffic from the LB to the ECS tasks"
vpc_id = module.vpc.vpc_id
// Permite tráfego de entrada vindo do nosso Load Balancer
ingress {
from_port = 8080 // A porta da nossa aplicação
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.lb_sg.id] // Apenas o LB pode acessar
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "ecs-tasks-sg"
}
}
3. Definindo o aws_ecs_service
Agora que temos o roteamento de tráfego configurado, podemos finalmente criar o recurso aws_ecs_service. Ele vai unir o cluster, a definição da tarefa e o load balancer.
Take full control of ecs fargate using terraform
Para uma explicação visual e detalhada sobre como criar um serviço ECS com Terraform, assista a esta seção do vídeo "Take full control of ecs fargate using terraform".
Assista do timestamp 06:03 a 11:17. O vídeo aborda a criação do recurso aws_ecs_service, destacando parâmetros importantes como launch_type, task_definition, desired_count e a integração com o load_balancer.
Vamos agora adicionar o recurso do serviço ao nosso arquivo ecs.tf.
Mastering AWS ECS Configuration with Terraform
O artigo "Mastering AWS ECS Configuration with Terraform" também fornece um excelente exemplo de como definir o serviço.
Leia a seção "Creating an ECS Service". Observe como o recurso aws_ecs_service conecta o cluster, task_definition, load_balancer e network_configuration.
Adicione o seguinte bloco de código ao seu arquivo ecs.tf, após a task_definition:
// ecs.tf (adicionar após o recurso aws_ecs_task_definition)
resource "aws_ecs_service" "app_service" {
name = "my-dotnet-api-service"
cluster = aws_ecs_cluster.app_cluster.id
task_definition = aws_ecs_task_definition.app_task.arn
desired_count = 2 // Queremos 2 instâncias da nossa API rodando
launch_type = "FARGATE"
network_configuration {
subnets = module.vpc.private_subnets // Colocamos as tarefas em sub-redes privadas por segurança
security_groups = [aws_security_group.ecs_tasks_sg.id]
}
load_balancer {
target_group_arn = aws_lb_target_group.app_tg.arn
container_name = "my-dotnet-api-container" // Nome do contêiner da nossa Task Definition
container_port = 8080 // Porta do contêiner
}
// Ajuda a evitar problemas quando o Terraform tenta substituir o serviço
// enquanto o ALB ainda está drenando as conexões.
depends_on = [aws_lb_listener.http]
tags = {
Name = "my-dotnet-api-service"
}
}
Vamos analisar as partes mais importantes:
clusteretask_definition: Referenciam os recursos que criamos anteriormente, conectando o serviço ao cluster e ao blueprint da aplicação.desired_count = 2: Instruímos o ECS a executar e manter duas instâncias (tarefas) da nossa API.launch_type = "FARGATE": Especificamos que queremos usar o modo de execução serverless.network_configuration: Definimos que nossas tarefas serão executadas nas sub-redes privadas (private_subnets) e usarão o grupo de segurançaecs_tasks_sgque criamos, que só permite tráfego vindo do nosso load balancer.load_balancer: É aqui que a mágica acontece. Ligamos o serviço ao Target Group do nosso ALB, especificando o nome e a porta do contêiner que deve receber o tráfego.
Teste seu entendimento!
No recurso aws_ecs_service, por que normalmente colocamos as tarefas em sub-redes privadas (private_subnets) em vez de públicas? Qual é o papel do NAT Gateway nesse cenário?
Show answer
Colocamos as tarefas em sub-redes privadas por segurança, seguindo o princípio do menor privilégio. Elas não precisam de um endereço IP público, pois o único tráfego de entrada que devem receber é o do Application Load Balancer, que atua como um ponto de entrada controlado.
No entanto, as tarefas ainda podem precisar de acesso à internet para, por exemplo, puxar a imagem do contêiner do ECR, chamar APIs de terceiros ou baixar pacotes. O NAT Gateway, que reside em uma sub-rede pública, permite que os recursos nas sub-redes privadas iniciem conexões de saída para a internet, mas impede que a internet inicie conexões de entrada com eles. O tráfego de saída das tarefas é roteado para o NAT Gateway, que então o envia para a internet.
4. Provisionando e Verificando
Agora que todos os nossos recursos estão definidos, é hora de aplicar as mudanças.
-
Inicializar: Como adicionamos novos
security_groupsque dependem do módulo VPC, é uma boa prática garantir que tudo esteja atualizado.terraform init -upgrade -
Planejar: Execute o
terraform planpara ver o que será criado. Você deve ver os novos recursos:aws_lb,aws_lb_target_group,aws_lb_listener, os doisaws_security_groupe, finalmente, oaws_ecs_service. -
Aplicar: Se o plano estiver correto, aplique-o.
terraform applyConfirme com
yes. O Terraform começará a provisionar a infraestrutura. Isso pode levar alguns minutos. -
Verificar: Após a conclusão, vá para o console da AWS:
- EC2 > Load Balancers: Encontre seu novo ALB. Copie seu
DNS name. - EC2 > Target Groups: Selecione seu Target Group. Na aba "Targets", você deverá ver duas novas entradas (os IPs das suas tarefas). Elas podem estar no estado
initialouunhealthypor um momento. - ECS > Clusters: Clique no seu cluster, vá para a aba "Services" e selecione seu serviço. Você deve ver que o
Desired statusé 2 e, após um tempo, oRunningtambém deve ser 2.
- EC2 > Load Balancers: Encontre seu novo ALB. Copie seu
Importante: Se na lição anterior você ainda não fez o push da sua imagem Docker .NET para o repositório ECR, as tarefas falharão ao iniciar (pending -> stopped) porque o ECS não conseguirá encontrar a imagem. Além disso, o health check do Target Group falhará, e as tarefas serão marcadas como unhealthy. Isso é esperado! No momento, estamos focados em garantir que a infraestrutura seja criada corretamente.
Conclusão
Parabéns! Você acaba de implantar uma aplicação em contêiner funcional e gerenciada na AWS usando Terraform. Você não apenas definiu o que executar, mas também como executá-lo, mantê-lo saudável e expô-lo ao mundo de forma segura.
Principais Pontos:
- O
aws_ecs_serviceé o recurso que gerencia o ciclo de vida das tarefas, garantindo que o número desejado (desired_count) esteja sempre em execução. - A exposição de um serviço à internet é feita através de um Application Load Balancer (ALB), configurado com um
Listenere umTarget Group. - A segurança é aprimorada colocando tarefas em sub-redes privadas e usando Security Groups para permitir tráfego apenas do ALB.
- O bloco
load_balancerdentro doaws_ecs_serviceé a cola que conecta o serviço aoTarget Group, permitindo que o tráfego seja roteado para as tarefas.
Próxima Lição:
Nossa configuração está funcionando, mas está cheia de valores fixos ("hardcoded"). Na próxima lição, vamos refatorar nosso código para gerenciar a configuração com variáveis do Terraform e expor detalhes importantes dos recursos usando outputs. Isso tornará nosso código mais reutilizável, flexível e fácil de gerenciar.