Introdução
A Engenharia de Software é um campo acelerado e competitivo. Lançar seus produtos para os usuários mais rapidamente lhe dará uma vantagem sobre seus concorrentes. Pelo lado positivo, as melhores práticas do setor estão em vigor para ajudar as empresas a competir em pé de igualdade.
A Integração Contínua e o Desenvolvimento Contínuo (CICD) é um exemplo de estratégia que aproveita as melhores práticas do setor para dar às empresas uma vantagem neste campo competitivo.
O GitHub, um repositório baseado na web com o Git, uma ferramenta de controle de versão, permite que desenvolvedores de software, engenheiros e arquitetos implementem CI/CD. O Desenvolvimento Contínuo (CD) é a prática de automatizar compilações, testes e implantações. A Integração Contínua (CI) permite que várias pessoas colaborem no mesmo projeto e verifiquem se o código está funcionando sem se preocupar com conflitos de mesclagem.
O GitHub Actions nos permite escrever etapas que automatizam compilações, testes e implantação.
Neste tutorial, você aprenderá como configurar a Integração Contínua com o GitHub Actions. Começaremos configurando um repositório Git para hospedar nosso código. Em seguida, configuraremos um processo de CI do GitHub para monitorar alterações em nosso código, iniciar um runner de CI para executar testes, compilar e implantar nossa aplicação em um servidor Ubuntu 22.04 executando o Nginx.
Pré-requisitos
Para acompanhar este tutorial, você precisará do seguinte:
-
Um servidor executando o Ubuntu 22.04. Você pode seguir este tutorial para a configuração inicial do servidor Ubuntu, adicionar um usuário não-root, e ativar o firewall UFW do Ubuntu.
-
Você precisará do Node.js instalado em seu servidor, de preferência na versão 14 ou superior. Temos um tutorial sobre como instalar o Node.js no Ubuntu.
-
Você precisará do software de servidor Nginx instalado. Temos um guia sobre Como Instalar o Nginx em um servidor executando o Ubuntu.
-
Você precisará do Docker e do Docker Compose instalado em sua máquina local para executar um ambiente de desenvolvimento isolado. Siga nosso tutorial para aprender Como Instalar e Operar o Docker na nuvem.
Agora que temos tudo o que precisamos, vamos começar.
Passo 1. Clonando o Repositório do Projeto.
Vamos basear este tutorial no Reactjs, uma biblioteca Javascript declarativa para construir interfaces de usuário. Se você quiser configurar um novo projeto do zero, pode usar este recurso sobre Como Configurar um App React. Para fins de brevidade, usaremos um clone deste repositório React.js que já configuramos no GitHub.
A aplicação que estamos clonando é uma aplicação React simples com react-router 6 e um teste feito com React Testing Library, que nos fornece métodos para acessar o DOM.
Para clonar o repositório, clique no botão verde e copie a URL.

Abra o terminal em seu espaço de trabalho e execute o comando abaixo para clonar o app:
|
1 |
git clone git@github.com:EspiraMarvin/cicd-tut.git |
Depois de clonar o repositório, navegue até o diretório do projeto:
|
1 |
cd cicd-tut |
Execute o comando docker-compose up para compilar e executar o app:
|
1 |
docker-compose up --build --force-recreate |
Quando o processo for concluído, acesse http://localhost:3000
Você deve ver algo semelhante a isto:

Passo 2. Entendendo o Arquivo Node.js.yml.
Nesta etapa, definiremos as diretivas no arquivo YAML do GitHub para nos ajudar a entender o que está acontecendo. No repositório, há um diretório .github/workflows que contém um node.js.yml arquivo, que possui etapas de fluxo de trabalho que os runners do GitHub seguem depois que você envia alterações para o seu repositório de código no GitHub. YAML a sintaxe é usada para escrever fluxos de trabalho para o GitHub Actions. Os arquivos YAML terminam com uma extensão yaml ou yml.
Abra o node.js.yml arquivo, ele deve se parecer com isto:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
name: cicd-tut on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: build: # O tipo de runner em que o job será executado runs-on: self-hosted strategy: matrix: node-version: [16.x] # Os passos representam uma sequência de tarefas que serão executadas como parte do job steps: - name: 'checkout' uses: actions/checkout@v3 - name: 'configurar ações do node' uses: actions/setup-node@v3 with: node-version: "16" cache: 'npm' - run: npm i - run: npm test - run: npm run build # - run: cp -r ~/actions-runner/cicd-react/react-tut-test/react-tut-test/build /var/www/react-cicd |
No momento da escrita deste tutorial, estávamos usando a versão 16 do Node.js 16. Agora, vamos entender o workflow do GitHub Actions:
-
name
name: cicd-tut
O nome do seu workflow, este nome será exibido no seu repositório Actions aba.
-
on
|
1 2 3 4 5 |
on: push: branches: [ "main" ] pull_request: branches: [ "main" ] |
on é usado para definir eventos. Os eventos podem acionar automaticamente um workflow ou ser agendados para mais tarde. Os eventos podem ser únicos ou múltiplos, você também pode especificar execuções de workflow para branches, tags ou arquivos específicos. Isso funciona como um filtro.
No nosso arquivo YAML, estamos definindo múltiplos eventos automáticos, que são:
-
Um push evento é acionado quando o código é enviado (committed) para um repositório
-
Um pull_request evento é acionado quando um pull request é criado na branch main.
Estamos especificando um nome de branch main para restringir a execução do workflow apenas a essa branch. Também podemos especificar branches a serem ignoradas usando a flag ! seguida pelo nome da branch.
-
jobs
Um workflow é essencialmente composto por um ou vários jobs. Esses jobs são executados em sucessão, do primeiro ao último.
|
1 2 3 4 |
jobs: build: # O tipo de runner em que o job será executado runs-on: self-hosted |
Cada job é executado em um ambiente de runner especificado por runs-on. Você pode optar por executar os jobs em runners do GitHub indicados por ubuntu-latest ou em um runner self-hosted indicado por self-hosted. Sua escolha dependerá do número de jobs que você precisa. Com runners self-hosted, você tem mais flexibilidade e controle dos recursos.
No nosso próximo passo, executaremos nossos jobs primeiro nos runners do GitHub e, mais tarde, configuraremos um runner self-hosted do GitHub em nosso próprio servidor.
-
strategy
A estratégia (strategy) nos permite usar variáveis em uma única definição de job para criar automaticamente múltiplas execuções de job baseadas nas combinações de variáveis.
No nosso arquivo YAML, temos uma variável para a nossa node-version, mas se adicionarmos outra para a versão 18 do node, assim: node-version: [16.x, 18.x], então a estratégia de matriz (matrix strategy) criará 2 execuções de job para a nossa aplicação react, tanto para a versão 16 quanto para a 18 do node.
|
1 2 3 |
strategy: matrix: node-version: [16.x] |
-
steps
Os passos (steps) são uma sequência de tarefas que compõem um job. Os passos podem executar comandos, configurar tarefas, executar ações em seu repositório público ou ações publicadas em um registro do docker.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
steps: - name: 'checkout' uses: actions/checkout@v3 - name: 'configurar ações do node' uses: actions/setup-node@v3 with: node-version: "16" cache: 'npm' - run: npm i - run: npm test - run: npm run build |
Uma etapa tem um nome. Embora seja opcional, você pode usá-lo para especificar uma maneira fácil de identificar o nome da sua etapa que será exibido no Github.
Em uma etapa, você pode selecionar uma ação para executar em seu trabalho, as ações são reutilizáveis. As versões da ação são especificadas ao definir uma ação, isso é importante porque evita que seu fluxo de trabalho quebre quando o proprietário da ação publica uma atualização.
No trecho de código acima, checkout@v3 é um exemplo de uma ação com uma versão especificada 3. Esta ação faz o checkout do seu repositório para que seu fluxo de trabalho possa acessá-lo.
Algumas ações como o actions/setup-node@v3 acima têm entradas indicadas usando a with palavra-chave, as ações do setup node exigem a versão 16 do node e que o npm seja armazenado em cache.
-
run
Esta ação executa programas de linha de comando usando o shell do sistema operacional.
No arquivo YAML acima, temos três comandos, ambos serão executados usando o mesmo shell no ambiente do runner.
-
O primeiro comando npm i instala todas as dependências necessárias para a nossa aplicação react.
-
O segundo npm test, executa o teste que escrevemos. O teste espera que o texto learn react seja renderizado na página inicial.
-
Por fim, npm run build o comando cria um diretório de build com uma compilação de produção da nossa aplicação. Mais tarde, usaremos este diretório de build em nosso bloco de servidor Nginx.
Passo 3. Testando o Github CI com GitHub Runners.
Neste passo, testaremos o processo de Integração Contínua com os runners do GitHub. Comece abrindo o arquivo node.js.yml. Modifique o tipo de runner no qual as ações serão executadas para ubuntu-latest. O objetivo disso é testar se o fluxo de trabalho do GitHub está funcionando perfeitamente nos runners do GitHub antes de configurar nossos próprios runners auto-hospedados.
|
1 2 3 |
jobs: build: runs-on: ubuntu-latest |
Crie um novo repositório em sua conta do GitHub. Antes de continuar, volte para o diretório do seu espaço de trabalho e exclua o diretório .git, se você não conseguir vê-lo, verifique seus arquivos ocultos. Você pode usar o seguinte comando em seu terminal para excluir o diretório:
|
1 |
rm -rf .git |
Agora você pode adicionar todos os arquivos do seu projeto com git add, fazer o commit e enviá-los para o seu repositório. Se tiver dúvidas, use este guia sobre conectar a pasta do seu projeto ao repositório do GitHub que você criou acima.
Quando terminar, clique na aba Code no seu repositório, e você verá um pequeno ponto laranja ao lado da contagem total de commits. Ao clicar nele, você verá um modal semelhante ao abaixo, indicando que seu fluxo de trabalho foi colocado na fila:

Agora clique no link Details no modal ou vá para a aba Actions, você verá cada etapa do fluxo de trabalho node.js.yml sendo executada pelos runners do GitHub:

Se for bem-sucedido, clique na aba Actions, ela deve se parecer com isso:

E é isso, o pequeno ponto laranja na nossa aba Code agora deve ser um visto verde. O GitHub runner compilou nossa aplicação com sucesso.
Agora, vamos dar um passo adiante e alterar o ambiente de build para usar runners auto-hospedados do GitHub em nossa própria Infraestrutura de Servidor Ubuntu.
Passo 4. Configurando o fluxo de trabalho do GitHub para usar um runner auto-hospedado.
Antes de instalarmos o runner auto-hospedado em nosso servidor, vamos voltar ao nosso espaço de trabalho e editar o arquivo de fluxo de trabalho node.js.yml para ser executado em runners auto-hospedados do GitHub.
|
1 2 3 |
jobs: build: runs-on: self-hosted |
Nesta etapa, quando você fizer o commit das alterações, o trabalho será colocado na fila, pois um runner auto-hospedado ainda não foi definido.
No seu repositório, clique na aba
Settings, na barra lateral esquerda clique em
Actions, depois clique em
Runners:

Clique em New self-hosted runner, e selecione Linux como o sistema operacional.
Você verá instruções mostrando como baixar o runner e instalá-lo em seu servidor.
Passo 5. Instalando e configurando um runner auto-hospedado do GitHub em nosso servidor.
Nesta etapa, configuraremos um runner auto-hospedado do GitHub. Um runner auto-hospedado é um sistema que pode implantar e gerenciar a execução de jobs do GitHub Actions no site do GitHub. Uma vantagem que o runner auto-hospedado tem sobre o runner hospedado pelo GitHub é a flexibilidade. Ele oferece mais controle sobre o sistema operacional, hardware e outras ferramentas que podem ser personalizadas para atender às necessidades da sua aplicação.
Os runners auto-hospedados podem ser adicionados em vários níveis, tais como:
-
Runners no nível do repositório, que são dedicados a um único repositório.
-
Runners no nível da organização, que podem processar jobs para múltiplos repositórios em uma organização.
-
Nível empresarial, que podem ser atribuídos a múltiplas organizações.
Para continuar, faça login no seu servidor via ssh:
|
1 |
ssh username@server_ip |
Mude para o seu diretório home com o comando:
|
1 |
cd ~ |
Em seguida, crie um diretório chamado action-runners e navegue para dentro dele:
|
1 |
mkdir actions-runner && cd actions-runner |
Em seguida, baixe a versão mais recente do pacote do runner:
|
1 |
curl -o actions-runner-linux-x64-2.298.2.tar.gz -L https://github.com/actions/runner/releases/download/v2.298.2/actions-runner-linux-x64-2.298.2.tar.gz |
Em seguida, extraia o pacote baixado com o comando:
|
1 |
tar xzf ./actions-runner-linux-x64-2.298.2.tar.gz |
De volta ao seu repositório, na aba Settings, no painel lateral esquerdo clique em Actions, depois em Runners, assim como fizemos no Step 4.
Você verá um comando listado que inclui um token vinculando seu runner auto-hospedado ao seu repositório do GitHub. Ainda dentro do diretório onde você extraiu o código do runner do GitHub, use o comando listado para vincular seu runner, por exemplo:
|
1 |
./config.sh --url https://github.com/EspiraMarvin/react-tut-test --token XXXXXXXXXXXXXXXXXXXXXXXXXXX |
Ele deve se autenticar com sucesso:

Pressione enter para o grupo de runner Default.
Em seguida, insira um nome para o seu runner, por exemplo, my-runner, e pressione enter.
Pressione Enter para pular a adição de marcadores adicionais, você deverá ver a mensagem de sucesso na captura de tela abaixo:

Insira o nome do seu diretório de trabalho, por exemplo, react-cicd, deve ser bem-sucedido com o texto settings saved.
Finalmente, execute ./run.sh, isso deve mostrar Connected to Github:

Mas isso não roda em segundo plano, se digitarmos ctrl+c em nosso terminal, o runner será interrompido, precisamos substituí-lo pelo serviço .svc.sh para manter o runner rodando como um serviço para que possamos continuar interagindo com ele.
Pare o runner com ctrl+c. Você pode instalar o serviço .svc.sh executando o comando:
|
1 |
sudo ./svc.sh install |
Depois de instalado, inicie o serviço com o comando:
|
1 |
sudo ./svc.sh start |
Isso deve ser bem-sucedido, mostrando active (running).
Para confirmar que o serviço svc.sh está ativo e rodando, execute o comando:
|
1 |
sudo ./svc/sh status |

Neste ponto, qualquer workflow que possa ter sido enfileirado aguardando por um runner auto-hospedado deve ser executado com sucesso. Você também pode editar um arquivo e testar as coisas. Por exemplo, modifique o arquivo Sobre.tsx, faça o commit e o push das alterações, o runner auto-hospedado concluirá o job com sucesso.
Passo 6. Configurando o bloco de servidor do Nginx
Nesta etapa, configuraremos um bloco de servidor no Nginx para visualizar a versão de build da nossa aplicação React. Temos um tutorial sobre Configurando blocos de servidor do Nginx que você pode achar útil.
Abaixo está um exemplo de um bloco de servidor usado neste tutorial:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
server { listen 80; listen [::]:80; server_name react.test; root /var/www/react-cicd/build; index index.html index.htm index.nginx-debian.html; add_header X-Frame-Options "SAMEORIGIN"; add_header X-XSS-Protection "1; mode=block"; add_header X-Content-Type-Options "nosniff"; charset utf-8; location / { try_files $uri $uri/ =404; } } |
Você criará um arquivo de configuração de bloco de servidor Nginx dentro do /etc/nginx/sites-available diretório.
Abra um arquivo para a configuração do bloco de servidor do seu site com o editor nano usando o comando:
|
1 |
sudo nano /etc/nginx/sites-available/react-cicd |
Copie o bloco de servidor compartilhado acima, modifique-o de acordo com os caminhos dos seus diretórios e cole-o no arquivo aberto. Quando terminar de editar, pressione ctrl+x depois pressione y e enter para salvar e sair.
Depois de salvo, crie um link simbólico para a configuração do bloco de servidor react-cicd de /etc/nginx/sites-available para /etc/nginx/sites-enabled executando o comando:
|
1 |
sudo ln -s /etc/nginx/sites-available/react-cicd /etc/nginx/sites-enabled/ |
Para que as alterações tenham efeito, você precisa reiniciar o Nginx. No entanto, antes de reiniciar o serviço Nginx, teste se as configurações do Nginx são válidas, executando o comando:
|
1 |
sudo nginx -t |
Se a configuração estiver correta, o teste deverá ser bem-sucedido.
Observe o valor da diretiva server_name “ react.test ” no bloco de servidor? Você adicionará esse valor no seu arquivo hosts na sua máquina local. Isso permitirá que você abra a aplicação no seu navegador. Esta etapa só é necessária para domínios virtuais usados em ambientes de desenvolvimento local. Se você tiver um nome de domínio registrado vinculado a um IP público do seu servidor, o nome de domínio já deverá estar acessível no seu navegador.
Na sua máquina local, abra o arquivo hosts com o comando:
|
1 |
sudo nano /etc/hosts |
Dentro do arquivo hosts, adicione o endereço IP do seu servidor, por exemplo, 127.0.0.1, seguido pelo seu nome de domínio virtual.
Um exemplo é mostrado abaixo. Em seguida, feche o arquivo e salve:
|
1 |
192.168.3.123 react.test |
De volta ao seu servidor, dentro do diretório /var/www , crie um novo diretório, você pode nomeá-lo como react-cicd executando:
|
1 |
mkdir react-cicd |
Nesta etapa, vamos descomentar o último comando no arquivo node.js.yml .
Este comando copia a pasta build da nossa aplicação react de onde especificamos nossa pasta de trabalho dentro do diretório actions-runner na step 5.
E coloca a pasta public no diretório /var/www/react-cicd .
O bloco de servidor agora pode acessar nossa aplicação e exibi-la em um navegador.
Por fim, reinicie o serviço Nginx com o comando:
|
1 |
sudo service nginx restart |
Agora, você pode fazer uma alteração no arquivo Sobre.tsx, depois fazer o commit e push das suas alterações para o seu repositório. Após uma compilação bem-sucedida, você verá a versão de build da sua aplicação react em http://react.test ou no nome de domínio que você especificou. Evite editar o elemento href no arquivo Home.tsx, pois isso pode fazer com que o teste já escrito falhe. A aba Actions no seu repositório também deve mostrar a compilação do job concluída.

Conclusão
A integração contínua com o Github Actions traz muitas vantagens, incluindo uma boa experiência para o desenvolvedor, ajuda com testes contínuos, permite colaborações mais fáceis em equipes maiores, reduz o tempo de desenvolvimento, lançamentos rápidos de novos recursos, feedback em tempo real e satisfação do cliente, dando a você uma vantagem sobre seus concorrentes. Para aprofundar esse conhecimento, você também pode querer aprender sobre Configurando Pipelines de Integração Contínua (CI) do GitLab no Ubuntu. e usando uma Instância Autogerenciada do GitLab para hospedar suas Imagens Docker e executar builds privadas.
Boa computação!
Comentários
Nenhum comentário ainda. Seja o primeiro.