Fala pessoal! Preparei um post bem legal sobre um dos assuntos que eu mais gosto: Pipelines e Containers! Esse post é o resultado de uma PoC que eu elaborei utilizando os melhores recursos da AWS relacionados a Containers, precisamente o ECS com o AWS Fargate.  Tentei resumir o máximo possível e detalhar a maior parte em código, todos os exemplos estão públicos no Github.

Considerações iniciais

  • A ideia desse projeto foi criar o bootstrap de uma pipeline completa integrada com CI (Github), testes unitários, build e deploy de containers.
  • Esse projeto roda uma pequena aplicação em Node.js
  • Dentro do repositório da aplicação, irá conter o Dockerfile responsável pelo build da aplicação.
  • Caso você queira realizar o deploy dessa mesma aplicação, será necessário fazer o Fork desse repositório.
  • Nosso projeto será entregue na AWS, ou seja, a máquina na qual você vai executar as ações de apply do Terraform vão precisar ter as roles ou access keys com permissões necessárias nos módulos de VPC, ECS, ECR, EC2, Codepipeline, Codebuild e S3.

Essa demonstração irá utilizar dois repositórios:

Pipeline de Deploy

A pipeline de deploy é bem simples. Ele será integrado ao Github, sempre que alguma ação acontecer na branch master do repositório, será enviado um webhook para o Codepipeline que irá iniciar todos os nossos steps como Build da imagem, testes unitários, push pro ECR até o deploy da nossa nova imagem para produção em um serviço do nosso cluster de ECS utilizando o AWS Fargate.

ECS-Deploy

Arquitetura da Aplicação

A arquitetura de produção dessa aplicação também é bem simples, e irá contar com os componentes:

  • Uma VPC simples, apenas com subnets publicas. Isso poderá ser editado no módulo de vpc do projeto.
  • Um cluster de ECS
  • Um service de aplicação rodando dentro do nosso Cluster. Esse service irá utilizar o AWS Fargate.
  • Um ALB que irá realizar balanceamento de carga entre os dois containers da nossa aplicação.

ECS-Arquitetura

Hand’s On!

1 – Github Access Token

Você vai precisar de um Access Token da sua conta do Github para realizar o build desse projeto. Para gerar sua Access Token, basta seguir os passos deste link.

Após ter em mãos sua key do Github, basta exportá-lo como variável de ambiente.

export GITHUB_TOKEN=3de88fac586410c123kasl129e5c614d935a91hgf

2 – Clonando o projeto

Vamos fazer o clone do projeto que contém as especificações da nossa Pipeline e do nosso cluster de ECS.

git clone https://github.com/msfidelis/ecs-pipeline

3 – Customizando o projeto.

3.1 – Customizações básicas.

Dentro do projeto, você poderá encontrar o arquivo variables.tf. Tomei o cuidado de colcoar a maioria das especificações do nosso projeto dentro dele de forma organizada. Editando o mesmo, você deverá informar:

  • Nome do seu cluster
  • Nome do seu repositório no ECR
  • Nome do seu container de aplicação
  • Quantidade de tasks (containers) que serão utilizados na nossa aplicação
  • Limite de unidades de CPU e quantidade de memória utilizada em cada task
  • Usuário, repositório e branch do projeto no Github
  • Porta do Load Balancer (listener)
  • Porta do containers (target)
vim variables.tf

Captura de Tela 2018-06-03 às 21.01.32

Captura de Tela 2018-06-03 às 21.00.32

3.2 – Customizações do Build

Um pouco mais a fundo nas struturas de pastas, podemos encontrar o arquiteo buildspec.yml dentro da pasta ecs-pipeline/modules/pipeline/templates/buildspec.yml

Este arquivo está customizado para o build de aplicação de exemplo. Nele estão descritas os steps de pre_build, onde vamos instalar as dependências necessárias, o build onde vamos rodar os testes unitários do projeto e o post_build, onde vamos criar a imagem final e fazer o push para o repositório do ECR com a nova versão da aplicação.

vim modules/pipeline/templates/buildspec.yml
version: 0.2

phases:
  pre_build:
    commands:
      - pip install awscli --upgrade --user
      - echo `aws --version`
      - echo Installing Node 8
      - curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
      - apt-get install -y nodejs  
      - echo Logging in to Amazon ECR...
      - $(aws ecr get-login --region ${region} --no-include-email)
      - REPOSITORY_URI=${repository_url}
      - IMAGE_TAG=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
      - echo Entered the pre_build phase...
      - npm install
  build:
    commands:
      - echo Build started on `date`
      - echo Starting Unit Tests
      - npm run unit-test
      - echo Building the Docker image...
      - docker build -t $REPOSITORY_URI:latest .
      - docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
  post_build:
    commands:
      - echo Build completed on `date`
      - echo Pushing the Docker images...
      - docker push $REPOSITORY_URI:latest
      - docker push $REPOSITORY_URI:$IMAGE_TAG
      - echo Writing image definitions file...
      - printf '[{"name":"${container_name}","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
    
artifacts:
  files: imagedefinitions.json

Fazendo o deploy do projeto

terraform apply

Captura de Tela 2018-06-03 às 21.27.54

Podemos conferir o deploy do nosso cluster de exemplo dentro do painel do ECS.

Captura de Tela 2018-06-03 às 21.29.24

Após o deploy,  será iniciado o primeiro build automaticamente, sem necessidades de nenhuma ação no repositório. Podemos olhar dentro do painel do CodePipeline o andamento da nossa pipeline.

 

 

Testando a aplicação

Podemos testar a aplicação

curl churrops-demo-alb-568936138.us-east-1.elb.amazonaws.com/ | json

Captura de Tela 2018-06-03 às 21.38.46

Essa aplicação de exemplo possui o resource /system, que nos entrega algumas informações do sistema e do container de execução, como hostname, S.O., memória, CPU e etc. Execute algumas vezes para ter certeza que as requisições estão sendo atendidas por mais de um container.

curl churrops-demo-alb-568936138.us-east-1.elb.amazonaws.com/system

Captura de Tela 2018-06-03 às 21.35.23

Testando o Hook do Github

Para testar a integração com o Github, vamos fazer qualquer edição no código da aplicação. Pra esse exemplo vou editar o endpoint base da aplicação e trocar a mensagem.

Captura de Tela 2018-06-03 às 21.46.49

Criei um Pull Request simples e fiz um merge com a branch master no nosso projeto. Dessa forma o Github irá disparar um hook contra nossa pipeline no CodePipeline e disparar um novo build do projeto.

Captura de Tela 2018-06-03 às 21.49.42

Captura de Tela 2018-06-03 às 21.52.35

Dessa forma, podemos conferir o estado do deployment nos services do nosso cluster e no painel do CodePipeline, como fizemos da primeira vez.

Captura de Tela 2018-06-03 às 22.00.06.png

 

 

Vamos testar novamente o mesmo endpoint.

curl churrops-demo-alb-568936138.us-east-1.elb.amazonaws.com/ -i

Captura de Tela 2018-06-03 às 21.57.36

Agora temos todo um ambiente de CI & CD completo entregando containers com qualidade e em produção utilizando containers Docker na AWS. Você pode ter mais detalhes de como funciona o projeto, até pra dar uma customizada conforme suas necessidades através do repositório do mesmo.

 

Destruindo o projeto

Minha parte favorita do Terraform

terraform destroy

Espero ter ajudado! 😀