Automatizando o deploy com GitHub Actions e Azure AppService
Como configurar e automatizar o deploy de uma aplicação Node.js na Azure App Service utilizando o GitHub Actions.

Para alguns desenvolvedores, talvez com maior tempo de atuação, o processo de deploy foi algo que fazia parte da lista de tarefas. Em algum momento os desenvolvedores tinham que fechar o pacote e utilizar por exemplo, um FTP para efetuar o upload dos arquivos para o servidor.
Efetuar deploys manualmente pode não ser um bom processo, já que é suscetível a erros operacionais, falhas humanas. Por sorte, atualmente as ferramentas DevOps estão bem evoluídas e repletas de integrações que podem facilitar nossa vida, incluíndo a automação no processo de deploy.
Neste texto será abordado como configurar o deploy automático no Azure App Service a partir de um repositório no GitHub.
Criando o repositório
O primeiro passo para a construção do cenário de estudo é criar o repositório no GitHub, o processo é bem simples e direto:

Clonando o repositório
Com o repositório criado, efetuaremos o clone através do seguinte comando:
$ git clone https://github.com/marcelovismari/consolelog-github-actions-appservice-azure.git
Cloning into 'consolelog-github-actions-appservice-azure'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (4/4), done.
Criando Hello World em Node.js
Abaixo acessamos o diretório onde o repositório foi clonado, verificamos a versão do Node.js e finalmente criamos um novo projeto com o npm init
:
$ cd consolelog-github-actions-appservice-azure/
$ node --version
v18.12.1
$ npm init -y
Abrindo o projeto no VSCode, adicionei uma nova linha no arquivo package.json
e alterei o nó scripts
, ficando da seguinte forma:
{
"name": "consolelog-github-actions-appservice-azure",
"version": "1.0.0",
"description": "Projeto exemplificando o deploy automático de uma API em Node.js no Azure AppServices",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/marcelovismari/consolelog-github-actions-appservice-azure.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/marcelovismari/consolelog-github-actions-appservice-azure/issues"
},
"homepage": "https://github.com/marcelovismari/consolelog-github-actions-appservice-azure#readme",
"type": "module"
}
Criando o arquivo index.js:
import { createServer } from "http";
const PORT = process.env.PORT || 8080;
const server = createServer((_, response) => {
response.writeHead(200, {
"Content-Type": "application/json",
});
response.write(
JSON.stringify({ mensagem: "Hello world" })
);
response.end();
});
server.listen(PORT, () => console.log(`Listening ${PORT}`));
Para executar o projeto basta executar o comando npm start
. Na sequência efetuei um simples GET através do CURL:
$ curl localhost:8080
{"mensagem":"Hello world"}%
Agora que o projeto está funcionando é só efetuar o commit e push. Na sequência vamos configurar o serviço na Azure.
Observação: na linha const PORT = process.env.PORT || 8080;
primeiro tentamos pegar o número da porta da variável de ambiente PORT
, caso não tenha um valor o número 8080
será adotado como valor. O motivo é que por padrão o App Service configura o valor da porta nesta variável de ambiente.
App Service sets the environment variablePORT
in the Node.js container, and forwards the incoming requests to your container at that port number. To receive the requests, your app should listen to that port usingprocess.env.PORT
https://learn.microsoft.com/en-us/azure/app-service/configure-language-nodejs?pivots=platform-linux#get-port-number
Azure AppService
A Azure fornece uma série de serviços, mas para este cenário de estudo vamos utilizar o App Service, que é categorizado como um serviço como plataforma (PaaS - Plataform as a Service). Neste tipo de serviço o desenvolvedor deve se preocupar com a aplicação e seus dados, deixando a responsabilidade de gerenciar a rede, sistema operacional, virtualização e outros pontos para a Azure.


Configurando o AppService na Azure
Acessando o portal da Azure podemos utilizar a barra de busca superior e procurar pelo App Services como a imagem abaixo ilustra:

Observação: é necessário ter uma subscrição (subscription) configurada.
Na sequência será carregado um formulário, que está preenchido na imagem abaixo:

Do formulário acima:
- Subscription - refere-se a sua subscrição, é uma espécie assinatura onde a Azure irá cobrar pelos serviços.
- Resource Group - é um agrupador lógico de recursos. Ajuda bastante na organização. Criei um novo agrupador,
consolelog-temporario
, para facilitar na hora da exclusão, ou seja, quando finalizar os testes basta remover este resource group e todos os serviços vinculados à ele também serão removidos. - Runtime stack - como vamos trabalhar com uma aplicação Node.js, basta selecionar a versão desejada.
- Pricing plan - como vamos efetuar apenas alguns testes selecionei o Free F1 (Shared infrastructure)
The Free and Shared (preview) service plans are base tiers that run on the same Azure VMs as other apps. Some apps may belong to other customers. These tiers are intended to be used only for development and testing purposes. There is no SLA provided for Free and Shared service plans. Free and Shared plans are metered on a per App basis.
https://azure.microsoft.com/en-us/pricing/details/app-service/windows/
Para deixar o processo bem simples, pulei as opções e fui direto para o Review + create para ser direcionado para a tela de revisão:

Após clicar no botão Create é necessário aguardar alguns instantes.

Após a conclusão da criação do recurso, podemos clicar no botão Go to resource que aparece na tela para visualizar os detalhes do recém-criado App Service.
Na página do recurso podemos observar algumas informações interessantes, como a URL de acesso:

Copiando a URL e colando no navegador, podemos ver uma página padrão, já que ainda não subimos nenhum código.

Configurando o deploy
Agora vamos para a parte interessante! O GitHub possui um recurso chamado Actions, que permite a automação de tarefas, dentre elas, o deploy. Para nossa sorte, a Azure já faz essa configuração no GitHub Actions de forma simples. Então vamos configurar o deploy da forma padrão (sem customizações) através do menu Deployment Center, como a imagem abaixo mostra:

Analisando o formulário temos o seguinte:
- Source - onde o código fonte está hospedado
- Signed in as - conta no GitHub que está vinculada à Azure
- Repository - nome do repositório onde está o código fonte
- Branch - branch onde está o código fonte
Após preencher o formulário é só clicar no botão Save na parte superior esquerda do formulário. Na sequência podemos visualizar os detalhes na aba Logs:


Após a conclusão do deploy podemos consultar novamente a URL da nossa aplicação:

Testando o deploy automático
Voltando ao código fonte, se você efetuar o git pull
perceberá a presença de uma nova pasta chamada .github
, com a subspasta workflows
e um arquivo chamado main_consolelog-webapp-1.yml
. Dentro deste arquivo há uma configuração para que a cada push efetuado na branch main, seja feito um novo deploy:
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy Node.js app to Azure Web App - consolelog-webapp-1
on:
push:
branches:
- main
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Node.js version
uses: actions/setup-node@v1
with:
node-version: '18.x'
- name: npm install, build, and test
run: |
npm install
npm run build --if-present
npm run test --if-present
- name: Upload artifact for deployment job
uses: actions/upload-artifact@v2
with:
name: node-app
path: .
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'Production'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Download artifact from build job
uses: actions/download-artifact@v2
with:
name: node-app
- name: 'Deploy to Azure Web App'
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
with:
app-name: 'consolelog-webapp-1'
slot-name: 'Production'
publish-profile: ${{ secrets.AZUREAPPSERVICE_PUBLISHPROFILE_1231212312312312 }}
package: .
Este arquivo pode ser criado manualmente para realizar outras tarefas como builds, testes, etc. Neste caso o arquivo foi criado no momento em que fizemos a configuração de deploy na Azure.
Para testar a configuração de deploy é bem simples, basta efetuar alguma alteração no código fonte e efetuar o push para o repositório. Neste caso alterei a resposta de Hello world
para Hello world 123
:
import { createServer } from "http";
const PORT = process.env.PORT || 8080;
const server = createServer((_, response) => {
response.writeHead(200, {
"Content-Type": "application/json",
});
response.write(
JSON.stringify({ mensagem: "Hello world 123" })
);
response.end();
});
server.listen(PORT, () => console.log(`Listening ${PORT}`));
Após o push
, é possível acompanhar no GitHub o workflow de deploy na aba Actions:

Quando o workflow for finalizado com sucesso, significa que o deploy foi efetuado. Testando no navegador:

Considerações
O objetivo era mostrar uma forma simples de como configurar um deploy de um repositório no GitHub para o serviço App Service da Azure.
Deixo como sugestão explorar um pouco mais o GitHub Actions e os serviços da Azure. Inclusive para novos usuários a Azure concede 200 USD para testar os serviços:
