Use Cases

Claude Code × AWS ECS/Fargate Guia Completo | Automatize Implantações de Containers

Automatize implantações no AWS ECS/Fargate com Claude Code. De definições de tarefas e configuração de serviços a implantações Blue/Green e infraestrutura CDK — baseado na experiência real de Masa.

“Quero executar containers na AWS, mas a configuração do ECS é complexa demais” — essa é a barreira que muitos desenvolvedores encontram no início. Definições de tarefas, serviços, clusters, load balancers, auto scaling… há tantas configurações que não se sabe por onde começar.

Tenho construído ambientes de containers serverless com ECS/Fargate no trabalho, e desde que passei a usar o Claude Code para descrever minha arquitetura e gerar tudo, desde definições de tarefas até código CDK, as implantações ficaram muito mais fáceis. Este artigo explica os passos práticos.


Fundamentos do ECS/Fargate em 3 Minutos

Cluster:          A "caixa" onde os containers ECS são executados
Task Definition:  Especificação do container (imagem, CPU, memória, variáveis de ambiente)
Service:          Define quantas tasks executar (inclui auto scaling)
Fargate:          Motor de execução de containers serverless — sem gerenciamento de servidor

Ao contrário do EC2, o Fargate não requer provisionamento de servidor nem gerenciamento de patches. Você pode se concentrar completamente na configuração do container.


Passo 1: Gerar Automaticamente uma Task Definition

claude -p "
Gere uma task definition do ECS em JSON com os seguintes requisitos:

- App: API Node.js (porta 3000)
- CPU: 512 (0.5 vCPU)
- Memória: 1024 MB
- Variáveis de ambiente: DATABASE_URL (obtida do Secrets Manager), NODE_ENV=production
- Log: CloudWatch Logs (grupo de logs /ecs/myapp)
- Health check: endpoint /health, intervalo de 30 segundos
- Imagem do container: 123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
- Execution role: ecsTaskExecutionRole
- Task role: myapp-task-role (acesso ao DynamoDB e S3)
"

Task definition gerada:

{
  "family": "myapp-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789:role/myapp-task-role",
  "containerDefinitions": [
    {
      "name": "myapp",
      "image": "123456789.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest",
      "portMappings": [{ "containerPort": 3000, "protocol": "tcp" }],
      "environment": [{ "name": "NODE_ENV", "value": "production" }],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789:secret:prod/database-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/myapp",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      }
    }
  ]
}

Passo 2: Construir Infraestrutura ECS/Fargate com CDK

Além da task definition, vamos gerar o cluster, o serviço e o ALB de uma só vez com CDK.

claude -p "
Implemente o seguinte ambiente ECS/Fargate em CDK TypeScript em lib/ecs-stack.ts:

- VPC: Importar VPC existente (obter vpcId da variável de ambiente)
- Cluster ECS: Somente Fargate
- Task Definition: Mesma especificação gerada acima
- ALB: HTTPS (obter ARN do certificado ACM da variável de ambiente), HTTP redireciona com 301
- Service: Auto scaling com mínimo 2, máximo 10 tasks
  - Scale out em 70% de utilização de CPU
  - Target tracking scaling
- Suporte a implantação Blue/Green (integração com CodeDeploy)
- Exibir status do serviço em um painel do CloudWatch
"
// lib/ecs-stack.ts
import * as cdk from "aws-cdk-lib";
import * as ec2 from "aws-cdk-lib/aws-ec2";
import * as ecs from "aws-cdk-lib/aws-ecs";
import * as ecsp from "aws-cdk-lib/aws-ecs-patterns";
import * as acm from "aws-cdk-lib/aws-certificatemanager";

export class EcsStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Importar VPC existente
    const vpc = ec2.Vpc.fromLookup(this, "Vpc", {
      vpcId: process.env.VPC_ID!,
    });

    // Cluster ECS
    const cluster = new ecs.Cluster(this, "Cluster", {
      vpc,
      clusterName: "myapp-cluster",
      containerInsights: true,  // Ativar CloudWatch Container Insights
    });

    // Certificado ACM
    const certificate = acm.Certificate.fromCertificateArn(
      this, "Certificate",
      process.env.CERTIFICATE_ARN!
    );

    // Task Definition
    const taskDef = new ecs.FargateTaskDefinition(this, "TaskDef", {
      cpu: 512,
      memoryLimitMiB: 1024,
    });

    const container = taskDef.addContainer("app", {
      image: ecs.ContainerImage.fromEcrRepository(
        ecr.Repository.fromRepositoryName(this, "Repo", "myapp")
      ),
      environment: { NODE_ENV: "production" },
      logging: ecs.LogDrivers.awsLogs({ streamPrefix: "ecs" }),
      healthCheck: {
        command: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        interval: cdk.Duration.seconds(30),
        timeout: cdk.Duration.seconds(5),
        retries: 3,
        startPeriod: cdk.Duration.seconds(60),
      },
    });
    container.addPortMappings({ containerPort: 3000 });

    // ALB + Fargate Service (conciso com patterns)
    const service = new ecsp.ApplicationLoadBalancedFargateService(
      this, "Service", {
        cluster,
        taskDefinition: taskDef,
        desiredCount: 2,
        certificate,
        redirectHTTP: true,
        publicLoadBalancer: true,
      }
    );

    // Configuração de Auto Scaling
    const scaling = service.service.autoScaleTaskCount({
      minCapacity: 2,
      maxCapacity: 10,
    });
    scaling.scaleOnCpuUtilization("CpuScaling", {
      targetUtilizationPercent: 70,
      scaleInCooldown: cdk.Duration.seconds(60),
      scaleOutCooldown: cdk.Duration.seconds(60),
    });

    // Output
    new cdk.CfnOutput(this, "LoadBalancerDns", {
      value: service.loadBalancer.loadBalancerDnsName,
    });
  }
}

Passo 3: Construir Pipeline CI/CD com GitHub Actions

claude -p "
Crie o seguinte pipeline CI/CD com GitHub Actions:

1. Gatilho no push para a branch main
2. Build da imagem Docker e push para o ECR
3. Atualizar a tag de imagem na task definition do ECS com o novo SHA
4. Implantar a nova task definition no serviço ECS
5. Notificar o Slack ao concluir a implantação

Ambiente: ap-northeast-1, nome do repositório ECR: myapp
"
name: Deploy to ECS

on:
  push:
    branches: [main]

env:
  AWS_REGION: ap-northeast-1
  ECR_REPOSITORY: myapp
  ECS_CLUSTER: myapp-cluster
  ECS_SERVICE: myapp-service
  CONTAINER_NAME: app

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build, tag, and push image to ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - name: Download task definition
        run: |
          aws ecs describe-task-definition --task-definition myapp-task \
            --query taskDefinition > task-definition.json

      - name: Update ECS task definition with new image
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ steps.build-image.outputs.image }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true

      - name: Notify Slack on success
        if: success()
        uses: slackapi/slack-github-action@v1
        with:
          webhook: ${{ secrets.SLACK_WEBHOOK }}
          payload: |
            {"text": "✅ Deployed to ECS: ${{ github.sha }}"}

Passo 4: Configurar Implantação Blue/Green

claude -p "
Gere código CDK e um arquivo AppSpec para configurar a implantação Blue/Green (CodeDeploy) para um serviço ECS.
Condição de rollback: fazer rollback automaticamente se um alarme do CloudWatch disparar dentro de 5 minutos após a implantação.
"
# appspec.yaml (para CodeDeploy)
version: 0.0
Resources:
  - TargetService:
      Type: AWS::ECS::Service
      Properties:
        TaskDefinition: <TASK_DEFINITION>
        LoadBalancerInfo:
          ContainerName: app
          ContainerPort: 3000
        PlatformVersion: LATEST
Hooks:
  - BeforeAllowTraffic: "arn:aws:lambda:ap-northeast-1:123456789:function:health-check"
  - AfterAllowTraffic: "arn:aws:lambda:ap-northeast-1:123456789:function:smoke-test"

As 5 Armadilhas Mais Comuns

1. Esquecer o startPeriod no health check

Os containers Fargate executam health checks imediatamente ao iniciar, mas se a aplicação for lenta para iniciar, ela é marcada como UNHEALTHY instantaneamente. Configure startPeriod: 60 (segundos) para dar tempo à aplicação inicializar.

2. Confundir o task role com o execution role

executionRole (ecsTaskExecutionRole): Permissões necessárias para iniciar o container
  → Fazer pull da imagem do ECR, escrever no CloudWatch Logs

taskRole (myapp-task-role): Permissões utilizadas pela aplicação
  → Acesso ao DynamoDB, S3, SQS, etc.

É muito fácil adicionar permissões ao role errado.

3. Configuração do security group no modo de rede awsvpc

O Fargate exige o modo de rede awsvpc. Se você esquecer de restringir o security group do container para permitir apenas tráfego do ALB, o container ficará exposto diretamente à internet.

4. Execution role necessário para buscar no Secrets Manager

Para recuperar valores do Secrets Manager via secrets, o executionRole deve ter a permissão secretsmanager:GetSecretValue. A ausência dessa permissão é uma razão muito comum para containers falharem ao iniciar.

5. O problema de desired_count: 0 durante a implantação

Um serviço com mínimo 0 no auto scaling pode desligar todos os containers à noite, causando inicializações lentas de manhã. Configure o mínimo para pelo menos 2 em produção.


Resumo

TarefaContribuição do Claude Code
Geração de task definitionJSON completo apenas com os requisitos
Implementação CDKCluster, serviço, ALB, auto scaling gerados juntos
Configuração CI/CDGeração de workflow do GitHub Actions
Implantação Blue/GreenAppSpec e configuração CodeDeploy gerados automaticamente
Resolução de problemasIdentifica causa raiz e correções a partir de logs de erro

O ECS tem muitos itens de configuração, mas ao dizer ao Claude Code “quero este tipo de configuração”, você obtém uma configuração completa seguindo as melhores práticas. Começar com CDK é a abordagem mais fácil e recomendada.

Artigos Relacionados

Referências

#claude-code #aws #ecs #fargate #container #devops

Leve seu fluxo no Claude Code a outro nível

50 modelos de prompt testados em campo, prontos para colar direto no Claude Code.

Grátis

PDF gratuito: Cheatsheet do Claude Code em 5 minutos

Basta informar seu e-mail e enviamos na hora o cheatsheet em uma página A4.

Cuidamos dos seus dados pessoais e nunca enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro apaixonado por Claude Code. Mantém o claudecode-lab.com, uma mídia tech em 10 idiomas com mais de 2.000 páginas.