Implantando um app Node no Elastic Beanstalk com Gitlab CI
Quando escutamos “implantação” enquanto falamos sobre um novo projeto e a necessidade de colocá-lo no ar funcionando, começamos a pensar sobre todas as possíveis dores de cabeça que isso pode trazer. Certamente não existe nenhum processo de implantação sem obstáculos, mas existem maneiras de diminuí-los. Uma possibilidade de redução é por meio da automatização parcial ou total do processo de implantação e, é nesse contexto, que o Elastic Beanstalk e Gitlab entram em cena.
O AWS Elastic Beanstalk é um serviço de fácil utilização para implantação e escalabilidade de aplicações e serviços da web desenvolvidos com Java, .NET, PHP, Node.js, Python, Ruby, Go e Docker em servidores familiares como Apache, Nginx, Passenger e IIS.
GitLab é uma plataforma completa de DevOps entregue como uma única aplicação.
Ambas, em conjunto, nos dão a possibilidade de hospedar e manter a nossa aplicação em uma nuvem privada de forma automatizada. Para mostrar uma maneira de fazer isso, esse artigo vai demonstrar como criar e executar uma aplicação Node + Express em um ambiente Elastic Beanstalk. Para fazer o processo como um todo mais fácil de ser entendido e reproduzido, ele foi dividido em duas etapas: a primeira mostrando como criar um ambiente no Elastic Beanstalk e a segunda mostrando como atualizar esse ambiente diretamente do Gitalb com sua ferramenta CI.
Elastic Beanstalk
A criacão de um ambiente no Elastic Beanstalk pode ser feita de forma programática utilizando outros serviços da AWS como o CloudFormation ou manualmente no console da AWS. Aqui nós criaremos um diretamente no console AWS com uma configuração pré-definida de VPC e subrede.
Primeiro, clicamos em “Criar um novo ambiente” e escolhemos “Ambiente de servidor web” e, em seguida, definimos “Nome da aplicação”.
Agora nós definimos o “Nome do ambiente”, assim como o seu “Domínio”.
Após isso, iremos definir qual a plataforma que usaremos. Escolhemos “Managed platform”, pois queremos utilizar Docker com Amazon Linux 2 pensando em prover uma infraestrutura mais leve e atualizada possível para a instância.
O próximo passo é definir o código da aplicação a ser enviado para o ambiente. Três opções são dadas: “Sample application”, “Version label” or “Upload your code”. Sabendo que o Elastic Beanstalk utiliza o S3 para armazenar versões da aplicação, escolhemos criar um Bucket S3 e subir uma versão inicial nele para poder compartilhar seu “Public S3 URL”. Uma observação: esse “código da aplicação” é um “Source Bundle”, o que significa que deve ser um arquivo no formato ZIP ou WAR que, no nosso caso, precisa ter o código fonte e um Dockerfile para poder executar Docker.
O conteúdo dos arquivos é:
app.js
const express = require('express')
const app = express()
const APP_PORT = process.env.APP_PORT || 3000;app.get('/', (req, res) => {
res.send('Hello World!')
})app.listen(APP_PORT, () => {
console.log(`Running app at port:${APP_PORT}`)
})
Dockerfile
FROM node:10
WORKDIR /usr/src/app
COPY package*.json ./
RUN npm install
COPY . .
ENV APP_PORT 8080
EXPOSE 8080
CMD [ "node", "app.js" ]
dockerignore
node_modules
npm-debug.log
package.json
{
"name": "my-awesome-app",
"version": "1.0.0",
"description": "Hello World in Node with Express",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
}
}
Considerando que utilizaremos uma configuração de VPC e subrede customizada, precisamos escolher quais iremos usar indo em “Configure more options” antes de terminar o processo de criação.
Para isso, vá no cartão “Network” e clique em “Edit”.
Selecione a VPC e subrede(s) desejada.
Em seguida, precisamos definir qual grupo de segurança (security group) será atribuido a instância EC2. Vá no cartão “Instances” e escolha um grupo de segurança.
Agora aperte “Create environment”…
… e é isso! Finalmente!
Depois de esperar a execução do processo de construção da AWS você deve ver o seu ambiente dessa forma:
Com o ambiente Elastic Beanstalk criado o próximo passo é atualizá-lo por meio do Gitlab CI.
Gitlab CI
Para executar um pipeline do Gitlab CI para implantar a nossa aplicação no Elastic Beanstalk, primeiro precisamos ter instalado um Runner e, em seguida, colocar o arquivo “.gitlab-ci.yml“ na raíz do repositório:
O pipeline criado para essa implantação consiste em duas etapas (jobs): Primeiro, criamos uma versão de aplicação AWS com os nossos arquivos, ou seja, criamos um Source Bundle, enviamos para o nosso Bucket S3 e finalizamos criando a versão da aplicação. Por fim, a segunda etapa envia a versão de aplicação que criamos para o ambiente Elastic Beanstalk.
Adendo: Para criar um arquivo zip no contexto do CI usamos um código simples em python que nos ajuda a gerar o zip, como pode ser visto abaixo:
zip.py (Python 3.x)
import sys, shutil
shutil.make_archive(sys.argv[1], 'zip', '.')
Ao utilizar esse arquivo CI, você pode definir as variáveis diretamente no arquivo ou como variáveis de ambiente do Gitlab acessando o menu “Settings” > “CI/CD” > “Variables”. Fazendo detalhamento dos seus valores:
APP_NAME: Obtém o nome que está definido para o repositório. Deve ser o mesmo nome definido para a aplicação Elastic Beanstalk que contém o nosso ambiente criado.
APP_VERSION: Define a atual versão da nossa aplicação. Serve para ajudar no gerenciamento das versões da aplicação no S3 e na tela de visualização do ambiente no Elastic Beanstalk.
S3_BUCKET: Nome do bucket que armazenará a versão da aplicação.
AWS_ID: ID da conta AWS que hospeda o nosso ambiente Elastic Beanstalk.
AWS_ACCESS_KEY_ID: Representa o “login” ou “username” da sua conta AWS.
AWS_SECRET_ACCESS_KEY: Representa a senha da sua conta AWS.
AWS_REGION: É a região onde a aplicação Elastic Beanstalk foi criada. No nosso caso us-east-1.
AWS_PLATFORM: A plataforma escolhida para executar a aplicação.
Ao setar esses valores e colocando o arquivo no repositório, o pipeline será executado e, após o término com sucesso dos 2 jobs, você deverá ver isso:
Agora vá para seu ambiente Elastic Beanstalk. Ele deve estar atualizando com sua versão de aplicação gerada pelo pipeline.
Na imagem acima, dentro de “Running version” você pode ver que nossa aplicação foi atualizada. O padrão escolhido para nomear o “Source Bundle” foi: {APP_NAME}-{APP_VERSION}-{CI_PIPELINE_NUMBER}. Isso facilita o rastreio da versão e do pipeline que a gerou pelo número do pipeline, o que também permite ver o commit que disparou tal pipeline.
O divertido: para ver a aplicação funcionando, copie a URL definida para o ambiente Elastic Beanstalk e cole-a no seu browser ou aplicativo que execute requisições para chamar seu endpoint.
Como pode ser visto acima, você deverá ver um incrível “Hello World” (bom, é uma aplicação em Node de qualquer forma 😜)
Conclusão
Graças ao Elastic Beanstalk e Gitlab, nós podemos criar uma estrutura simples e automatizada para hospedar e manter nossa aplicação (nesse caso, uma aplicação Node, mas poderia ser em outras linguagens). Isso realmente ajuda na criação de um processo de implantação menos doloroso e pavoroso e também dá aos desenvolvedores mais tempo para focar na aplicação em si.
Como resultado, conseguimos que nossa aplicação possa ser executada em um ambiente seguro, controlado e escalável, e que pode ser atualizado de acordo com as características do projeto e, ao mesmo tempo, representa uma solução com ótimo custo-benefício.