Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions modules/ecs-service-update/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# AGENTS.md

Este arquivo orienta agentes de IA para implementar mudancas neste modulo Terraform com consistencia.

## Objetivo do modulo

Provisionar/atualizar um servico ECS Fargate (`aws_ecs_service`) com suporte a:
- rede (subnets/security groups/public IP)
- load balancer dinamico (1 ou N target groups)
- estrategia de capacidade com `FARGATE` e `FARGATE_SPOT`
- auto scaling opcional por CPU e memoria (`aws_appautoscaling_*`)

## Arquivos principais

- `main.tf`: recurso `aws_ecs_service` e configuracoes de deploy/capacity provider/load balancer.
- `auto-scaling.tf`: alvo e politicas de auto scaling (CPU e memoria), condicionais por `var.auto_scaling`.
- `variables.tf`: contrato de entrada do modulo (tipos, defaults e validacoes).

## Regras importantes para futuras alteracoes

1. Nao quebrar retrocompatibilidade de variaveis existentes.
2. Manter `deployment_circuit_breaker` habilitado com rollback.
3. Preservar logica condicional de `spot`:
- `spot = false`: usa `launch_type = "FARGATE"` e sem capacity providers.
- `spot = true`: `launch_type = null` e habilita `capacity_provider_strategy`.
4. Preservar fallback de load balancer:
- se `load_balancers` for informado, usar lista completa.
- senao, se `target_group_arn` existir, criar bloco unico com `service_name` e `container_port`.
5. Preservar validacao obrigatoria de tags: `owner`, `partner`, `business`, `product`.
6. Em novas variaveis:
- adicionar descricao clara
- definir `type`
- fornecer `default` quando fizer sentido
7. Se incluir novos recursos AWS, manter naming consistente com `service_name`.

## Checklist de implementacao

1. Atualizar `variables.tf` para qualquer novo input.
2. Atualizar `main.tf` e/ou `auto-scaling.tf` conforme feature.
3. Atualizar `README.md` (inputs, comportamento e exemplo).
4. Validar sintaxe com:
- `terraform fmt -recursive`
- `terraform validate`

## Ponto de atencao atual

- A variavel e o atributo usam `desire_count` (sem "d"). Nao renomear sem estrategia de migracao para evitar breaking change.

125 changes: 125 additions & 0 deletions modules/ecs-service-update/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# terraform-module ecs-service-update

Modulo Terraform para criar/atualizar um servico ECS Fargate com suporte opcional a:
- balanceamento de carga
- estrategia com FARGATE + FARGATE_SPOT
- auto scaling por CPU e memoria

## Recursos criados

- `aws_ecs_service.ecs_service_update`
- `aws_appautoscaling_target.ecs-target` (quando `auto_scaling = true`)
- `aws_appautoscaling_policy.ecs_policy_memory` (quando `auto_scaling = true`)
- `aws_appautoscaling_policy.ecs_policy_cpu` (quando `auto_scaling = true`)

## Requisitos

- Terraform compativel com uso de `optional(...)` em tipos de objeto.
- Provider AWS configurado no projeto consumidor.
- `task_definition_arn` ja existente.

## Uso basico

```hcl
module "ecs_service_update" {
source = "./modules/ecs-service-update"

service_name = "my-service"
cluster_name = "my-ecs-cluster"
task_definition_arn = "arn:aws:ecs:us-west-2:123456789012:task-definition/my-service:15"
subnets = ["subnet-aaa", "subnet-bbb"]
security_groups = ["sg-123"]
desire_count = 2
assign_public_ip = false
container_port = 8080
target_group_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tg/abc"
health_check_grace_period_seconds = 60

tags = {
owner = "team-platform"
partner = "engineering"
business = "core"
product = "checkout"
}
}
```

## Uso com Spot + Auto Scaling

```hcl
module "ecs_service_update" {
source = "./modules/ecs-service-update"

service_name = "my-service"
cluster_name = "my-ecs-cluster"
task_definition_arn = "arn:aws:ecs:us-west-2:123456789012:task-definition/my-service:15"
subnets = ["subnet-aaa", "subnet-bbb"]
security_groups = ["sg-123"]
desire_count = 2
assign_public_ip = false

spot = true
weight_fargate = 1
weight_fargate_spot = 2

auto_scaling = true
min_capacity = 2
max_capacity = 8
cpu_target = 60
memory_target = 80

load_balancers = [
{
container_name = "my-service"
container_port = 8080
target_group_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tg-a/aaa"
},
{
container_name = "my-service"
container_port = 8081
target_group_arn = "arn:aws:elasticloadbalancing:us-west-2:123456789012:targetgroup/tg-b/bbb"
}
]

tags = {
owner = "team-platform"
partner = "engineering"
business = "core"
product = "checkout"
}
}
```

## Inputs

| Nome | Tipo | Default | Obrigatorio | Descricao |
|---|---|---|---|---|
| `service_name` | `string` | n/a | sim | Nome do servico ECS. |
| `cluster_name` | `string` | n/a | sim | Nome do cluster ECS. |
| `task_definition_arn` | `string` | n/a | sim | ARN da task definition. |
| `subnets` | `list(string)` | n/a | sim | Subnets do servico. |
| `security_groups` | `list(string)` | n/a | sim | Security groups do servico. |
| `tags` | `map(string)` | n/a | sim | Tags do servico. Deve conter: `owner`, `partner`, `business`, `product`. |
| `container_port` | `number` | `null` | nao | Porta do container no fallback de LB simples. |
| `load_balancers` | `list(object)` | `null` | nao | Lista de LBs com `container_name` (opcional), `container_port`, `target_group_arn`. |
| `target_group_arn` | `string` | `null` | nao | Target group unico (fallback quando `load_balancers` nao e informado). |
| `desire_count` | `number` | `1` | nao | Quantidade desejada de tasks. |
| `assign_public_ip` | `bool` | `true` | nao | Define `assign_public_ip` no servico ECS. |
| `auto_scaling` | `bool` | `false` | nao | Habilita recursos de auto scaling. |
| `min_capacity` | `number` | `1` | nao | Minimo de tasks para auto scaling. |
| `max_capacity` | `number` | `4` | nao | Maximo de tasks para auto scaling. |
| `cpu_target` | `number` | `60` | nao | Alvo de utilizacao de CPU (%). |
| `memory_target` | `number` | `80` | nao | Alvo de utilizacao de memoria (%). |
| `spot_staging` | `bool` | `false` | nao | Ajusta pesos para staging (`FARGATE=1`, `FARGATE_SPOT=2`). |
| `spot` | `bool` | `false` | nao | Habilita capacity providers com Spot. |
| `weight_fargate` | `number` | `2` | nao | Peso do provider `FARGATE` quando `spot=true`. |
| `weight_fargate_spot` | `number` | `1` | nao | Peso do provider `FARGATE_SPOT` quando `spot=true`. |
| `health_check_grace_period_seconds` | `number` | `null` | nao | Define o grace period dos health checks do servico ECS; quando nao informado, o atributo permanece `null`. |

## Observacoes

- Este modulo nao declara `outputs.tf`.
- Nome da variavel: `desire_count` (sem "d"), manter esse nome para compatibilidade.
- Quando `spot = false`, o modulo usa `launch_type = "FARGATE"` e nao usa `capacity_provider_strategy`.
- Quando `spot = true`, o modulo usa `capacity_provider_strategy` e `launch_type = null`.
- `health_check_grace_period_seconds` so e aplicado quando informado; caso contrario, o provider recebe `null`.
11 changes: 6 additions & 5 deletions modules/ecs-service-update/main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
resource "aws_ecs_service" "ecs_service_update" {
name = var.service_name
cluster = var.cluster_name
task_definition = var.task_definition_arn
desired_count = var.desire_count
launch_type = var.spot ? null : "FARGATE"
name = var.service_name
cluster = var.cluster_name
task_definition = var.task_definition_arn
desired_count = var.desire_count
launch_type = var.spot ? null : "FARGATE"
health_check_grace_period_seconds = var.health_check_grace_period_seconds

network_configuration {
assign_public_ip = var.assign_public_ip
Expand Down
6 changes: 6 additions & 0 deletions modules/ecs-service-update/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,9 @@ variable "weight_fargate_spot" {
type = number
default = 1
}

variable "health_check_grace_period_seconds" {
description = "Tempo de grace period, em segundos, para os health checks do servico ECS."
type = number
default = null
}
55 changes: 55 additions & 0 deletions modules/ecs-task/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# AGENTS.md

Este arquivo orienta agentes de IA para implementar mudancas neste modulo Terraform com consistencia.

## Objetivo do modulo

Provisionar uma `aws_ecs_task_definition` Fargate com:
- definicao de container simples
- log no CloudWatch via `awslogs`
- suporte a `environment`, `secrets`, `command`, `entrypoint` e `workdir`
- fallback para porta unica ou lista de `port_mappings`
- role IAM da task com policies base e policies adicionais opcionais

## Arquivos principais

- `main.tf`: `aws_ecs_task_definition`, normalizacao de `port_mappings` e montagem de `container_definitions`.
- `variables.tf`: contrato de entrada do modulo.
- `iam.tf`: role IAM da task e anexos de policies.
- `data.tf`: data sources de conta, regiao e policy de logs.
- `output.tf`: saida do ARN da task definition.

## Regras importantes para futuras alteracoes

1. Nao quebrar retrocompatibilidade das variaveis existentes.
2. Preservar o comportamento de fallback de portas:
- se `port_mappings` estiver informado e tiver itens, usar essa lista
- senao, se `container_port` existir, gerar um unico `portMappings`
- senao, nao enviar `portMappings`
3. Preservar o filtro de campos `null` no `container_definitions`.
Campos opcionais como `command`, `entryPoint` e `workingDirectory` devem ser omitidos do JSON quando nao informados.
4. Manter consistencia dos nomes da API ECS no JSON do container:
- `entryPoint`
- `workingDirectory`
- `portMappings`
5. Se novas variaveis forem adicionadas ao container, atualizar:
- `variables.tf`
- `main.tf`
- `README.md`
6. Manter o mesmo role em `execution_role_arn` e `task_role_arn`, a menos que haja mudanca explicita de desenho.
7. Nao remover a dependencia da policy `ecs_task_cloudwatch_logs_policy` sem ajustar a documentacao e o consumo do modulo.

## Checklist de implementacao

1. Atualizar `variables.tf` para qualquer novo input.
2. Atualizar `main.tf` e/ou `iam.tf` conforme a feature.
3. Atualizar `README.md` com exemplo e tabela de inputs quando houver mudanca de contrato.
4. Validar com:
- `terraform fmt -check -diff`
- `terraform validate` (apos `terraform init`, quando provider estiver disponivel)

## Pontos de atencao atuais

- O nome da variavel `environment-variables` usa hifen. Nao renomear sem estrategia de migracao, mesmo nao sendo o padrao mais comum.
- O modulo usa `AmazonElasticContainerRegistryPublicReadOnly`. Se houver necessidade de ECR privado, revisar este anexo com cuidado antes de trocar.
- A policy `ecs_task_cloudwatch_logs_policy` e buscada por nome via data source e precisa existir na conta consumidora.
122 changes: 122 additions & 0 deletions modules/ecs-task/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# ecs-task

Modulo Terraform para criar uma `aws_ecs_task_definition` Fargate com configuracao simples de container, logs no CloudWatch, secrets e mapeamento de portas.

O modulo cria:
- `aws_ecs_task_definition.task_definition`
- `aws_iam_role.ecs_task_role`
- anexos de politica para execucao de task, ECR publico, Secrets Manager e logs

## Requisitos

- Terraform compativel com uso de `optional(...)` em tipos de objeto.
- Provider AWS configurado no projeto consumidor.
- Policy `ecs_task_cloudwatch_logs_policy` existente na conta.

## Uso basico

```hcl
module "ecs_task" {
source = "./modules/ecs-task"

family = "my-app"
image = "123456789012.dkr.ecr.us-west-2.amazonaws.com/my-app:1.0.0"

cpu = 256
memory = 512

environment-variables = [
{ name = "APP_ENV", value = "production" },
{ name = "LOG_LEVEL", value = "info" }
]

secrets = [
{
name = "DATABASE_URL"
valueFrom = "arn:aws:secretsmanager:us-west-2:123456789012:secret:database-url"
}
]

container_port = 8080
}
```

## Uso com `command`, `entrypoint` e `workdir`

```hcl
module "ecs_task" {
source = "./modules/ecs-task"

family = "worker"
image = "123456789012.dkr.ecr.us-west-2.amazonaws.com/worker:1.0.0"

command = ["bundle", "exec", "sidekiq"]
entrypoint = ["/bin/sh", "-lc"]
workdir = "/app"

cpu = 512
memory = 1024
}
```

## Uso com multiplos `port_mappings`

```hcl
module "ecs_task" {
source = "./modules/ecs-task"

family = "api"
image = "123456789012.dkr.ecr.us-west-2.amazonaws.com/api:1.0.0"

port_mappings = [
{
container_port = 8080
host_port = 8080
protocol = "tcp"
app_protocol = "http"
name = "api-http"
},
{
container_port = 9090
protocol = "tcp"
name = "api-metrics"
}
]
}
```

## Entradas

| Nome | Tipo | Padrao | Obrigatorio | Descricao |
|---|---|---|---|---|
| `family` | `string` | n/a | sim | Nome da task ECS. |
| `image` | `string` | n/a | sim | Imagem do container. |
| `environment-variables` | `list(object({ name = string, value = string }))` | `[]` | nao | Variaveis de ambiente do container. |
| `command` | `list(string)` | `null` | nao | Comando a ser executado no container. |
| `entrypoint` | `list(string)` | `null` | nao | Entrypoint do container. |
| `workdir` | `string` | `null` | nao | Diretorio de trabalho do container. |
| `cpu` | `number` | `256` | nao | CPU alocada para a task. |
| `memory` | `number` | `512` | nao | Memoria alocada para a task. |
| `container_port` | `number` | `null` | nao | Porta unica do container. Usada como fallback quando `port_mappings` nao for informado. |
| `port_mappings` | `list(object({ container_port = number, host_port = optional(number), protocol = optional(string), app_protocol = optional(string), name = optional(string) }))` | `null` | nao | Lista de mapeamentos de porta. Quando informada, substitui o fallback de `container_port`. |
| `protocol` | `string` | `"tcp"` | nao | Protocolo de rede usado no fallback de `container_port`. |
| `app_protocol` | `string` | `"http"` | nao | Protocolo de aplicacao usado no fallback de `container_port`. |
| `secrets` | `list(object({ name = string, valueFrom = string }))` | `[]` | nao | Lista de secrets do container. |
| `arn_attach_additional_policy` | `list(string)` | `[]` | nao | ARNs de policies adicionais para anexar ao role da task. |
| `cpu_architecture` | `string` | `"X86_64"` | nao | Arquitetura da CPU da task. |

## Saidas

| Nome | Descricao |
|---|---|
| `task_definition_arn` | ARN da definicao de task criada. |

## Observacoes

- O modulo cria uma task definition Fargate com `network_mode = "awsvpc"` e `operating_system_family = "LINUX"`.
- `command`, `entrypoint` e `workdir` sao opcionais. Quando o valor e `null`, a chave nao e enviada no `container_definitions`.
- Se `port_mappings` estiver vazio ou `null`, o modulo tenta montar um unico mapeamento a partir de `container_port`.
- Se `host_port` nao for informado em `port_mappings`, o modulo usa o valor de `container_port`.
- O log group e criado automaticamente pelo driver `awslogs` com `awslogs-create-group = "true"`.
- O mesmo role e usado em `execution_role_arn` e `task_role_arn`.

Loading