Há pouco mais de um mês eu comecei a ficar incomodado com a forma que estávamos fazendo deploy de uma aplicação de um cliente na Amazon. A aplicação rodava numa instância do EC2 configurada manualmente para rodar um ou dois containers. O deploy era feito com o famigerado shell script que conectava na instância, baixava a última versão da imagem e fazia restart dos containers. Não tínhamos um ambiente de staging, pipeline de deployment ou mesmo um gerenciador de secrets funcionando.
Essa situação começou a ficar cada vez mais incômoda a medida que a aplicação evoluía naturalmente. Mais secrets, mais containers e mais serviços em background para gerenciar me fizeram fazer a pergunta: “qual a forma menos burocrática de rodar essa aplicação na AWS?”. As opções que eu tinha eram:
A AWS certamente possui outros produtos similares que devem ter passado desapercebidos.
O nosso uso do copilot não foi o mais “next, next, next”. Tínhamos uma parte da infrastrutura já configurada com o Terraform/Terragrunt, portanto já tínhamos recursos como VPC (com subnets públicas e privadas), um cluster Aurora RDS, etc. Mesmo assim foi relativamente tranquilo de fazer nosso ambiente de staging:
copilot app init myapp
Esse comando cria uma pasta “copilot” na raiz do seu repositório com um arquivo
.workspace
contendo algumas informações (apenas o nome da aplicação no meu
caso). Você ainda pode passar a flag --domain
se tiver o domínio da sua
aplicação já configurado no Route53 e se quiser que o copilot aponte um
subdomínio (no formato {svcName}.{envName}.{appName}.{domain}, ex:
web.staging.myapp.dominio.com.br
) para seus serviços expostos via load
balancer.
copilot env init \
--import-vpc-id vpc-000 \
--import-public-subnets subnet-111,subnet-222 \
--import-private-subnets subnet-333,subnet-444 \
--name staging
Esse comando, um pouco mais complicado por causa dos recursos já existentes, inicializa um ambiente (staging no meu caso). O copilot cria (via CloudFormation) a VPC automaticamente se você não as especificar previamente. Além da VPC o Copilot também cria um cluster ECS utilizando o Fargate (serverless), papéis IAM e tudo mais o que é necessário para criar um ambiente isolado.
copilot svc init --name web --svc-type "Load Balanced Web Service" --dockerfile ./Dockerfile
Isso cria a pasta copilot/web
com um arquivo manifest.yml
e cria alguns
outros recursos, como um repositório de imagens do Docker no Elastic Container
Registry (ECR). O arquivo manifest.yml
vem mais ou menos assim por padrão:
# The manifest for the "web" service.
# Read the full specification for the "Load Balanced Web Service" type at:
# https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/
# Your service name will be used in naming your resources like log groups, ECS services, etc.
name: web
# The "architecture" of the service you're running.
type: Load Balanced Web Service
image:
# Docker build arguments.
# For additional overrides: https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/#image-build
build: ./Dockerfile
# Port exposed through your container to route traffic to it.
port: 80
http:
# Requests to this path will be forwarded to your service.
# To match all requests you can use the "/" path.
path: 'web'
# You can specify a custom health check path. The default is "/".
# For additional configuration: https://aws.github.io/copilot-cli/docs/manifest/lb-web-service/#http-healthcheck
# healthcheck: '/'
# You can enable sticky sessions.
# stickiness: true
# Number of CPU units for the task.
cpu: 256
# Amount of memory in MiB used by the task.
memory: 512
# Number of tasks that should be running in your service.
count: 1
# Optional fields for more advanced use-cases.
#
#variables: # Pass environment variables as key value pairs.
# LOG_LEVEL: info
#
#secrets: # Pass secrets from AWS Systems Manager (SSM) Parameter Store.
# GITHUB_TOKEN: GITHUB_TOKEN # The key is the name of the environment variable, the value is the name of the SSM parameter.
# You can override any of the values defined above by environment.
#environments:
# test:
# count: 2 # Number of tasks to run for the "test" environment.
Aqui o copilot já mostra uma utilidade imensa, pois ele cria um serviço no ECS, um load balancer com healthcheck e já configura os target groups do load balancer para apontar para o serviço do ECS. Muito provavelmente você vai precisar editar esse arquivo antes de executar o comando de deploy:
copilot svc deploy --name web -e staging
Esse comando faz uma série de coisas:
Repeti esse processo algumas vezes para adicionar os outros serviços e cronjobs. Algumas outras edições nos manifests me permitiram fazer o deploy para produção dois dias depois sem maiores problemas.
O que eu gostei
addons
e coloque arquivos de stack
do CloudFormation. Desta forma, você pode criar um arquivo addons/bucket.yml
e o copilot aplicará essa stack quando estiver fazendo deploy do seu serviço
e injetará qualquer output (ex: o nome do bucket, ou a url do servidor caso
você provisione um banco de dados) como variável de ambiente para sua
aplicação. Esse caso de adicionar um bucket é tão comum que o próprio copilot
já possui um comando próprio para criar o addon;O que eu achei mais ou menos
task run
é pesadão no heroku você pode rodar um heroku run bash
e um
terminal remoto a-la SSH é aberto para você. Na mesma pegada, o kubectl exec
permite executar comandos num pod. Com o copilot isso é MUITO MAIS
complicado, pois ele cria um repositório no ECR exclusivo para executar o
comando. Demora um bom tempo para fazer build e push da imagem e não há a
possibilidade de executar algum comando interativamente (como no heroku ou no
kubernetes).O que eu não gostei
Se você precisa rodar uma aplicação de média ou alta complexidade na AWS e acha que o Kubernetes pode ser uma alternativa muito pesada, então o ECS com o Copilot pode ser uma excelente alternativa.
Eu não testei o Elastic Beanstalk tanto quanto ele merecia ser testado, no entanto. Espero ter a chance de fazer um teste mais bem feito no futuro. Até lá eu acredito que ele seja uma alternativa viável mas que eu não conheço os problemas.