Implantando uma app Node no AWS Elastic Beanstalk com GitHub Actions
Com o passar do tempo, novas tecnologias e ferramentas surgem com o propósito de trazer mais rápidas e melhores soluções para os nossos problemas do dia-a-dia. No mundo da Integração Contínua e Entrega Contínua (CI/CD), a maioria dessas soluções visam automatizar o maior número de processos possível. Esse é o caso do GitHub Actions, a estrela desse artigo.
GitHub Actions é uma ferramenta provida pelo GitHub para automatizar workflows CI/CD de software permitindo a construção, teste e implantação do seu código armazenado no GitHub. Esses workflows são disparados por eventos do GitHub como “push”, “issue creation” ou “new release”, que permitem a personalização de diferentes workflows baseados nas características do projeto.
Ao mesmo tempo que Actions automatiza o pipeline de implantação, ele é manutenível e flexível, pois ele é operado por meio de comandos semelhantes ao que podemos executar em um terminal linux, da mesma forma que o Gitlab. Além disso, ele fornece uma vasta seleção de modelos prontos para diversas linguagens em qualquer SO, possuindo integração com diversos serviços em nuvem. Tudo isso para ajudar na construção de um workflow, o que significa que qualquer projeto hospedado no GitHub pode ter seu próprio workflow!
Baseado nessa ideia, esse artigo irá demonstrar um exemplo de GitHub Action para uma aplicação Node com Express que será implantada em um ambiente do Elastic Beanstalk da AWS.
Ambiente Elastic Beanstalk
Antes de ver e entender o workflow propriamente, precisamos ter um ambiente em operação e o bucket criado para receberem a nossa aplicação Node pelo GitHub Actions. A criação do bucket é realizada por uma questão de organização das versões da aplicação que podem vir a existir. Usaremos um simples “Hello World” em Node com Express para podermos focar na explicação do processo de implantação.
Portanto, para termos uma aplicação executando no Elastic Beanstalk, precisaremos criar um Source Bundle, que, no nosso caso, será um arquivo zip contendo um Dockerfile e o código fonte a ser executado pelo Dockerfile. Após criarmos a app localmente, esses devem ser os arquivos incluidos no Source Bundle:
O conteúdo desses arquivos é o seguinte:
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"
}
}
Com esses arquivos dentro de um arquivo zip (nomeado “my-awesome-app-v0.zip” para fins de demonstração), podemos acessar o AWS Elastic Beanstalk pelo console para criar o ambiente.
Primeiro, vamos no botão “Criar novo ambiente” (Create a new environment), escolher “Ambiente de servidor web” (Web server environment) e depois definir o nome da aplicação (Application name).
Em seguida, definiremos o nome do ambiente (Environment name), assim como o seu domínio (Domain).
Agora definiremos a plataforma na qual a aplicação ficará em execução. Selecionamos “Plataforma gerenciada” (Managed platform), pois queremos utilizar Docker com Amazon Linux 2 na tentativa de deixar a infraestrutura da instância o mais leve e atualizada possível.
O próximo passo é reunir o código a ser implantado no ambiente. Três opções são oferecidas, das quais escolhemos “Enviar seu código” (Upload your code) e selecionaremos o arquivo “my-awesome-app-v0.zip” previamente criado.
Sabendo que utilizaremos uma configuração de VPC e subrede customizada , devemos definir quais iremos usar indo em “Configurar mais opções” (Configure more options) antes de finalizar o processo de criação.
Para isso, iremos no cartão “Rede” (Network) e clicar em “Editar” (Edit).
Selecionar a VPC e subrede(s) desejadas.
Agora definiremos o grupo de segurança (security group) a ser usado pela nossa instância EC2. Basta ir no cartão “Instâncias” (Instances) e escolher um grupo de segurança EC2.
Clique em “Criar ambiente” (Create environment) e a criação do ambiente começará. Depois de esperar o processo de construção da AWS, você deverá ver seu ambiente da seguinte maneira:
Por fim, acessaremos o serviço S3 para criar um bucket que armazenará as futuras versões da aplicação. O seu nome deve ser exatamente o mesmo que definiremos no nosso arquivo de workflow. Nesse caso, nomeamos “my-awesome-app-bucket”.
As demais configurações do bucket podem ser deixadas com a marcação feita padrão. Com o ambiente Elastic Beanstalk e bucket criados, o próximo passo é atualizar a nossa aplicação por meio do GitHub Actions.
Entendendo o workflow
Em Actions, um workflow é definido em um arquivo YAML que descreve passos contendo um conjunto de comandos que criam o processo de pipeline CI/CD como um todo. Esse arquivo deve ser colocado dentro do diretório “.github/workflows” na raíz do repositório e o seu nome pode ser qualquer coisa (Ex: meu-workflow.yml). Nesse exemplo, coloquei o nome “node-deploy-aws-eb.yml”.
Apenas por uma questão de curiosidade, no Gitlab você descreve um pipeline também em um arquivo YAML, mas você pode ter apenas um único arquivo por repositório e na raíz do mesmo, além de possuir o nome “.gitlab-ci.yml”, enquanto no GitHub permite ter múltiplos arquivos em que cada um é disparado de acordo com o evento GitHub que você escolher para que inicie a execução (isso será destacado nos parágrafos seguintes).
Então, como iremos implantar uma aplicação Node em um ambiente Elastic Beanstalk da AWS, dividiremos nosso workflows em 2 tarefas nessa ordem:
- Criar versão Elastic Beanstalk: cria uma nova versão para a nossa aplicação do Elastic Beanstalk e a armazena no nosso bucket S3.
- Implantar no ambiente Elastic Beanstalk: Sobe a nova versão no ambiente da aplicação.
Para agilizarmos, o arquivo de workflow utilizado foi esse:
Explicando as partes do arquivo:
“name” é apenas uma descrição do arquivo.
“env” funciona como um namespace no qual você define variáveis de ambientes customizadas para serem usadas nos “steps”.
“on” funciona como um namespace no qual você define quais eventos GitHub irão disparar a execução desse workflow. “push”, “branches”, “[ main ]” determina que cada push feito na branch “main” disparará esse workflow.
“jobs”, define as tarefas a serem executadas no workflow. Duas tarefas foram definidas: “create_eb_version” and “deploy_aws”.
“runs-on” define a imagem(tipo de máquina) para executar a tarefa.
“needs” determina a dependência entre tarefas. Nesse caso, “deploy_aws” é executado apenas se “create_eb_version” tiver sido executado.
“uses: actions/checkout@v2” permite que o workflow acesse os arquivos do seu repositório.
“uses: actions/setup-python@v1” instala o python na máquina para que o “Elastic Beanstalk Cli” possa ser instalado para implantar a aplicação.
“uses: aws-actions/configure-aws-credentials@v1” se encarrega de realizar a autenticação da conta AWS.
“secrets” contém variáveis de ambiente encriptadas que possuem informações sensíveis.
Para definir essas variáveis dentro de “segredos” (secrets), basta irmos na aba “Configurações” (Settings), menu “Segredos” (Secrets) e clicar em “Novo segredo” (New repository secret). Para esse workflow, definimos as seguintes variáveis:
Com essas configurações realizadas, podemos fazer um push dos arquivos para o nosso repositório e ver o GitHub Actions em execução.
Quando as duas tarefas são executadas com sucesso, elas ganham um marcador verde (indicando sucesso) ao visualizar o pipeline inteiro.
Podemos verificar que tudo ocorreu como esperado indo no nosso bucket criado e observando o arquivo contendo a nova versão da aplicação armazenado lá.
E o nosso ambiente do Elastic Beanstalk atualizado com a mesma versão encontrada no bucket.
A hora da verdade chegou! Para ver a aplicação em execução, basta clicar na sua URL que veremos a famosa mensagem de “Hello World”.
Conclusão
Actions é uma ótima adição no GitHub, visto que oferece uma ferramenta de automação de CI/CD robusta e de fácil manutenção. Com ela, podemos ver o todo o processo de implantação, desde o commit do código até a atualização da app dentro do próprio GitHub, o que reduz as dificuldades e problemas gerados quando essa visualização depende de múltiplas ferramentas.
Apesar de ter sido lançado recentemente (Novembro 2019), Actions possui uma grande comunidade, que ajuda em sua evolução e dá suporte para usuários existentes e novos. Isso significa que daqui para a frente Actions só tem a melhorar.