Deploys manuais não escalam. Cada etapa manual é uma fonte potencial de erros e, quanto mais rápido o seu time entrega, mais esses erros se acumulam. Um pipeline de CI/CD construído sobre Docker e AWS remove o trabalho manual do caminho crítico: o código é compilado, testado, empacotado como container e implantado em produção sem intervenção humana em cada etapa.

Este post percorre um pipeline completo usando AWS CodePipeline, AWS CodeBuild, Amazon ECR e Amazon ECS.

Por que Docker e AWS para CI/CD?

Containers Docker oferecem comportamento consistente entre ambientes. O que roda localmente roda da mesma forma no CI e em produção. Os serviços AWS cuidam de escalonamento e segurança no nível de infraestrutura, e o CodePipeline une os estágios em um único fluxo de trabalho automatizado.

Pré-requisitos

  • Uma conta AWS com privilégios administrativos.
  • Conhecimento básico de Docker e conceitos de conteinerização.
  • Familiaridade com ECS e ECR.
  • Uma aplicação de exemplo (este guia usa Node.js).

Arquitetura do Pipeline

O pipeline possui três estágios:

  1. Source: O código é enviado para um sistema de controle de versão (AWS CodeCommit ou GitHub).
  2. Build: O CodeBuild constrói a imagem Docker e executa os testes.
  3. Deploy: A imagem é enviada para o ECR e o ECS a implanta em um cluster.

Etapa 1: Configurando o Repositório de Origem

Para uma integração perfeita com a AWS, o AWS CodeCommit é a escolha mais direta.

  1. Acesse o console do AWS CodeCommit.

  2. Crie um novo repositório chamado my-app-repo.

  3. Clone o repositório para sua máquina local:

    git clone https://git-codecommit.us-east-1.amazonaws.com/v1/repos/my-app-repo
  4. Adicione o código da sua aplicação e faça o push:

    git add .
    git commit -m "Initial commit"
    git push origin master

Etapa 2: Conteinerizando a Aplicação

Crie um Dockerfile para definir como sua aplicação é empacotada.

Dockerfile de exemplo para Node.js

# Use Node.js LTS version as the base image
FROM node:18-alpine

# Set the working directory in the container
WORKDIR /usr/src/app

# Copy package.json and package-lock.json
COPY package*.json ./

# Install dependencies
RUN npm install --production

# Copy the rest of the application code
COPY . .

# Expose the application port
EXPOSE 3000

# Start the application
CMD ["node", "app.js"]

Alguns pontos importantes: use uma imagem base mínima para manter a imagem pequena, copie apenas os arquivos necessários para otimizar o cache de build e execute containers como usuário não-root por segurança.

Etapa 3: Especificação de Build para o CodeBuild

O AWS CodeBuild precisa de um arquivo buildspec.yml na raiz do seu repositório.

buildspec.yml de exemplo

version: 0.2

phases:
  pre_build:
    commands:
      - echo Logging into Amazon ECR...
      - $(aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin <AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com)
      - REPOSITORY_URI=<AWS_ACCOUNT_ID>.dkr.ecr.us-east-1.amazonaws.com/my-app-repo
  build:
    commands:
      - echo Building the Docker image...
      - docker build -t $REPOSITORY_URI:latest .
  post_build:
    commands:
      - echo Pushing the Docker image...
      - docker push $REPOSITORY_URI:latest
artifacts:
  files:
    - '**/*'

Substitua <AWS_ACCOUNT_ID> pelo seu ID real de conta AWS.

Etapa 4: Configurando o Amazon ECR

O Amazon ECR armazena suas imagens Docker.

  1. Acesse o console do Amazon ECR.
  2. Crie um novo repositório chamado my-app-repo.
  3. Anote o URI do repositório para uso no buildspec.yml.

Etapa 5: Configurando o AWS CodeBuild

  1. Acesse o console do AWS CodeBuild.
  2. Crie um novo projeto de build chamado my-app-build.
  3. Configure:
    • Source Provider: AWS CodeCommit.
    • Repository: my-app-repo.
    • Environment: runtime Ubuntu Standard, Docker habilitado, modo Privileged ativado (necessário para builds Docker).
    • Buildspec: Use o buildspec.yml do código-fonte.

Etapa 6: Configurando o AWS CodePipeline

  1. Acesse o console do AWS CodePipeline.
  2. Crie um novo pipeline chamado my-app-pipeline.
  3. Estágio Source: AWS CodeCommit, my-app-repo, branch master.
  4. Estágio Build: AWS CodeBuild, projeto my-app-build.
  5. Estágio Deploy: AWS ECS, my-ecs-cluster, my-app-service.

Etapa 7: Configurando o Amazon ECS

Criando um Cluster ECS

  1. Acesse o console do Amazon ECS.
  2. Crie um cluster chamado my-ecs-cluster. Use Fargate se quiser evitar o gerenciamento de instâncias EC2.

Definindo uma Task Definition

  1. Acesse Task Definitions.
  2. Crie my-app-task com:
    • Task Role: IAM role com as permissões necessárias.
    • Network Mode: awsvpc para Fargate.
    • Container: nome my-app-container, imagem do ECR, porta 3000 mapeada para o host 80.

Criando um Service

  1. Acesse Services e crie my-app-service.
  2. Launch type: Fargate. Task definition: my-app-task. Habilite rolling updates.

Etapa 8: Testando o Pipeline

  1. Faça uma alteração no código localmente.

  2. Faça push para o master:

    git add .
    git commit -m "Updated application"
    git push origin master
  3. Acompanhe o progresso do pipeline no console do CodePipeline.

  4. Verifique o novo deploy no console do ECS.

Melhorando o Pipeline

Testes Automatizados

Adicione comandos de teste ao buildspec.yml antes da etapa de build Docker:

phases:
  build:
    commands:
      - echo Running unit tests...
      - npm test
      - echo Building Docker image...
      - docker build -t $REPOSITORY_URI:latest .

Infraestrutura como Código

Defina todos os recursos AWS em templates do CloudFormation ou Terraform. Manter o código de infraestrutura no controle de versão junto ao código da aplicação torna a configuração do ambiente reproduzível e as alterações auditáveis.

Gerenciamento de Dependências com CodeArtifact

O AWS CodeArtifact armazena e serve pacotes npm de forma privada. Isso é útil para compartilhar bibliotecas internas entre serviços sem publicá-las no registro público do npm.

Boas Práticas de Segurança

  • Atribua IAM roles com privilégios mínimos a cada componente do CodeBuild e ECS.
  • Armazene segredos no AWS Secrets Manager, não em variáveis de ambiente ou código-fonte.
  • Configure VPCs, subnets e security groups para restringir o acesso à rede.
  • Habilite CloudTrail e CloudWatch para logging de auditoria.

Monitoramento e Logging

  • O CloudWatch Logs coleta a saída das tasks do ECS.
  • O AWS X-Ray rastreia requisições pela aplicação implantada.
  • Configure o Amazon SNS para enviar notificações quando os estágios do pipeline falharem.

Otimização de Custos

  • Use capacidade Spot do ECS para workloads que tolerem interrupções.
  • Dimensione corretamente a CPU e memória das tasks com base nas métricas reais do CloudWatch, em vez de estimativas.
  • Revise e exclua regularmente imagens ECR não utilizadas e task definitions do ECS.

Conclusão

Uma vez que esse pipeline está no lugar, implantar uma alteração requer apenas um git push. O CodePipeline cuida do resto: constrói a imagem, executa os testes, faz o push para o ECR e implanta a nova versão no ECS. O custo de configuração é real, mas se paga rapidamente em tempo economizado e incidentes em produção evitados.