Esse site utiliza cookies
Nós armazenamos dados temporariamente para melhorar a sua experiência de navegação e recomendar conteúdo do seu interesse.
Ao utilizar os nossos serviços, você concorda com as nossas políticas de privacidade.
Esse site utiliza cookies
Nós armazenamos dados temporariamente para melhorar a sua experiência de navegação e recomendar conteúdo do seu interesse.
Ao utilizar os nossos serviços, você concorda com as nossas políticas de privacidade.
Postado em 06 julho 2023
Atualizado em 06 julho 2023
Esse projeto mostra como automatizar processos repetitivos após modificações de código. Esses processos podem ser teste, build, análise, detecção de bugs e muitas outras coisas. O repositório a ser usado será um sistema de ATM (caixa eletrônico) que foi desenvolvido nesse projeto.
O caixa eletrônico será integrado em um sistema de integração contínua (CI) que é um termo presente em CI/CD. O sistema de integração contínua será configurado na máquina local (localhost) e usará apenas serviços gratuitos de código aberto.
Nesse sistema serão usados três serviços de integração:
Os três sistemas acima serão configurados na máquina local. Os serviços nexus e sonarqube serão integrados ao jenkins. Quando jenkins iniciar uma tarefa (job), os outros serviços serão acionados.
Queremos que jenkins inicie uma tarefa (job) após enviarmos uma modificação ao repositório remoto (trigger). Uma forma fácil e prática de iniciar tarefas automaticamente é definindo e configurando o endereço em que Jenkins está operando no repositório remoto.
O caixa eletrônico será armazenado no GitHub, cujo serviço será nosso repositório remoto. Pelo fato que vamos operar o Jenkins no nosso ambiente local, ele será acessível apenas na nossa rede interna.
Precisamos disponibilizar o acesso externo ao Jenkins para que ele possa iniciar uma tarefa (job) automaticamente através do GitHub. Para isso, iremos precisar de outro serviço, o webhookrelay. O webhookrelay é um serviço disponível na nuvem que permite a integração de serviços que operam em uma rede interna. Em outras palavras, ele permitirá que Jenkins possa receber instruções de serviços externos mesmo operando em uma rede isolada.
A imagem acima mostra o ciclo da integração contínua:
Toda modificação enviada ao repositório remoto irá iniciar esse ciclo acima automaticamente.
Os seguintes serviços precisam ser instalados:
Gradle também será necessário para gerenciar o código e as bibliotecas. JUnit será usado para fazer testes. A linguagem de programação usada no caixa eletrônico é java, porém isso não será muito importante nesse projeto.
Esse sistema de integração contínua será rodado em um macOS Montrey versão 12.0.1. Dependendo do sistema operacional, alguns detalhes devem mudar.
Jenkins pode ser facilmente instalado no macOS usando o homebrew. Homebrew é um gerenciador de pacotes de código aberto.
$ brew -v
Homebrew 4.0.26-35-g9e257fc
A versão utilizada será a mostrada acima. Usuários de windows podem optar pelo chocolatey.
brew install jenkins-lts
O comando acima é o suficiente para a instalação de jenkins no mac. Para iniciar o serviço usamos os comandos abaixo:
brew services start jenkins-lts
Provavelmente jenkins irá operar na porta 8080. Na primeira vez que o Jenkins for acessado, ele irá exigir a senha inicial. A senha inicial pode ser obtida com o comando abaixo:
cat /Users/$nomedousuario/.jenkins/secrets/initialAdminPassword
O comando acima irá exibir a senha inicial no terminal e permitirá a definição da senha.
Sonarqube deve ser baixado diretamente no site oficial. Existe a versão “Community Edition” que é gratuita. Essa é a versão que estaremos usando.
Descompactamos o arquivo e colocamos dentro de um diretório de nossa preferência. No meu caso será em /Users/$nomedousuario. Em seguida, podemos inicializar sonarqube normalmente:
/Users/$nomedousuario/sonarqube-10.1.0.73491/bin/macosx-universal-64/sonar.sh console
Os usuários que usam outro sistema operacional, devem usar o arquivo sh em outro diretório:
$ pwd
/Users/$nomedousuario/sonarqube-10.1.0.73491/bin
$ ls
elasticsearch linux-x86-64 macosx-universal-64 windows-x86-64 winsw-license
Assim como Jenkins, sonarqube exigirá a criação de uma conta.
O código do caixa eletrônico será compilado para a linguagem do computador. Alguns módulos de java quando compilados se tornam arquivos jar. Esses arquivos jar serão armazenados no sonatype nexus. Na prática, esses artefatos podem ser baixados por outros membros da equipe para o uso imediato.
Assim como o sonarqube, o sonatype nexus também deve ser instalado pelo site oficial. Após ser baixado, ele deve ser descompactado no local de preferência.
Após a descompactação, sonatype nexus pode ser executado no diretório bin com o comando abaixo:
$ pwd
/Users/$nomedousuario/nexus-3.56.0-01-mac/nexus-3.56.0-01/bin
$ ./nexus start
Após a execução criamos uma conta e prosseguimos com a integração contínua.
Todos os três serviços após serem executados, estarão operando no fundo.
Serviço | Endereço e porta |
---|---|
Jenkins | localhost:8080 |
Sonatype Nexus | localhost:8081 |
Sonarqube | localhost:9000 |
O repositório que estaremos utilizando já está armazenado no github. Para evitar problemas, estaremos usando outra versão do repositório nesse branch.
Para testar o caixa eletrônico, primeiro temos que escrever o código para o teste. O conteúdo escrito não é muito importante nesse projeto. Basicamente, o conteúdo escrito nas classes de teste será o seguinte:
import org.junit.Test;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertEquals;
public class TransactionTest {
@Test
public void transactionMaximum() {
byte depositType = (byte) TransactionType.DEPOSIT.index;
Exception exception = assertThrows(Exception.class,
() -> TransactionInsertInputValidation.validate("1000", "10000", depositType));
assertEquals("Quantidade deve ser maior do que zero e menor do que 9999", exception.getMessage());
}
}
Cada função de teste espera um determinado valor. Caso esse valor não seja o esperado, o teste falha e o erro é reportado no relatório final. O teste é realizado na hora de fazer o build do projeto. Usando o gradle, é possível fazer o teste manualmente:
$ gradle build
BUILD SUCCESSFUL in 22s
7 actionable tasks: 7 executed
Porém, não queremos realizar o teste manualmente. Queremos automatizar esse processo. Para isso, criamos um pipeline no Jenkins.
O pipeline deve ser vinculado ao repositório do GitHub para que possamos obter o conteúdo armazenado (git pull).
Dentro do diretório absoluto do correio eletrônico, criamos um novo arquivo chamado “Jenkinsfile”. Nesse arquivo configuramos todos os estágios da tarefa (job) em etapas.
Primeiro, criamos a etapa para o build.
node {
stage('JUnit tests and build') {
withGradle {
sh './gradlew build --scan'
}
}
}
No código acima adicionamos uma etapa. O comando “gradlew build” tem a mesma função que “gradle build”. A opção “–scan” cria um relatório contendo o resultado dos testes.
Antes de tudo, na interface de Jenkins (Gerenciar Jenkins > Plugins), instalamos a seguinte extensão:
SonarQube Scanner for Jenkins Versão 2.15
Após adicionar a extensão acima no Jenkins, fazemos a transição para a tela de configurações do sistema (Gerenciar Jenkins > System). Nessa tela, procuramos por “SonarQube servers” e adicionamos a sua configuração. Os detalhes estão documentados no site de sonarqube.
Até aqui, a integração com Jenkins foi realizada. Porém, precisamos configurar o sonarqube para escanear o nosso código e encontrar vulnerabilidades. Dentro do arquivo “build.gradle” adicionamos o plugin de sonarqube:
plugins {
id "org.sonarqube" version "4.2.1.3168"
}
Ainda no mesmo arquivo, adicionamos algumas propriedades para Sonarqube.
sonar {
properties {
property "sonar.projectKey", "ATM"
property "sonar.projectName", "ATM"
}
}
A configuração acima será para o uso do gradle. Agora precisamos adicionar algumas etapas no arquivo “Jenkinsfile”.
node {
stage('SCM') {
checkout scm
}
stage('SonarQube Analysis') {
withSonarQubeEnv() {
sh "./gradlew sonar"
}
}
...
}
A etapa “SCM” é responsável por baixar o conteúdo do projeto dentro do repositório remoto e tornar o código disponível para as próximas etapas. A etapa “SonarQube Analysis” é onde sonarqube entra em ação e faz a checagem no código. A única coisa que falta é criar um projeto no sonarqube e definir a chave do projeto (project key) como definimos no Jenkinsfile (sonar.projectKey).
Sonatype nexus será responsável por armazenar artefatos gerados do aplicativo de caixa eletrônico. Bem parecido com uma nuvem que armazena arquivos.
Adicionamos mais duas etapas no Jenkinsfile, uma para criar o artefato e outra para armazenar o artefato.
node {
...
stage('Assembles jar') {
withGradle {
sh './gradlew jar'
}
}
stage('Upload') {
nexusPublisher nexusInstanceId: 'ATMRespository', nexusRepositoryId: 'maven-releases', packages: [
[$class: 'MavenPackage', mavenAssetList: [
[classifier: '', extension: '', filePath: '/Users/$nomedousuario/.jenkins/workspace/ATMSonarqube/app/build/libs/app.jar']
], mavenCoordinate: [artifactId: 'atm', groupId: 'com.dicionariotec.atm', packaging: 'jar', version: '1.0.0']]
]
}
}
A etapa “Assembles jar” usa um comando do gradle. A etapa “Upload” usa a extensão do sonatype nexus que adicionaremos daqui pra frente.
Na interface de Jenkins, acessamos a tela de plugins (Painel de controle > Gerenciar Jenkins > Plugins) e instalamos a extensão para sonatype nexus:
Nexus Platform Versão3.16.501.ve3d6b_58f1d37
Após instalar a extensão acima, devemos configurar a conexão entre os dois serviços. Para prosseguir, precisamos ter uma conta criada no Sonatype Nexus Repository que deve estar operando em localhost:8081. Essa conta será usada como credenciais para a conexão entre Jenkins e Sonatype Nexus.
Na tela de configuração do sistema (Gerenciar Jenkins > System), procuramos por “Nexus Repository Manager Servers” e adicionamos um novo servidor de sonatype. Ajuste os valores de acordo com o seu ambiente e contexto.
Após adicionar o servidor, podemos testar a conexão clicando no botão “Test connection”. Se houver problemas, cheque as credenciais e se o serviço está operando corretamente.
Ainda não configuramos o gatilho “trigger” para que a tarefa se inicie automaticamente. Porém, já podemos iniciar o processo manualmente clicando no botão de “build”.
Após apertar o botão acima, as etapas devem ser executadas uma por uma. Caso haja algum problema no meio do caminho o processo é interrompido. Caso não haja problemas, o resultado deve ser semelhante a figura abaixo:
Agora, a única configuração que está faltando é a automatização da tarefa após a realização de alguma modificação no código do repositório remoto.
Como já descrito no começo desse projeto, temos um pequeno problema em conectar o repositório armazenado no GitHub com o Jenkins que está rodando na nossa rede interna. O GitHub pode ser acessado por qualquer usuário, pois ele está na internet. Porém, Jenkins que está rodando na nossa rede interna só pode ser acessado por usuários que estão conectados dentro da mesma rede interna. Logo, github não pode acessar o nosso endereço (a menos que disponibilizamos a nossa rede para o acesso público). Esse problema pode ser resolvido com um serviço de redirecionamento de portas (Port Forwarding).
Antes de configurar o redirecionamento de portas, precisamos obter um endereço de conexão no Jenkins para possibilitar a conexão externa. Nas configurações da tarefa (job), procure pela opção “Dispare construções remotamente”, e em seguida defina um token arbitrário. Nesse exemplo usaremos “atmsonarqube”. Por isso, o endereço de conexão para trigger será “localhost:8080/job/ATMSonarqube/build?token=atmsonarqube”. Veja a estrutura abaixo:
http://localhost:$portaJenkins/job/$nomedatarefa/build?token=$tokenArbitrario
Após adicionar a configuração de conexão remota acima, podemos testar a conexão usando o curl:
curl -X POST --user $nomeusuario:$tokendousuario http://localhost:8080/job/ATMSonarqube/build?token=atmsonarqube
O parâmetro “tokendousuario” deve ser criado nas configurações do usuário do Jenkins (Painel de controle > $usuario > Configure). Dentro da tela de configuração do usuário procuramos por “Passe de API” e adicionamos um passe de API apertando o botão “Adicionar novo passe”. Um token será criado e será usado no lugar do parâmetro “tokendousuario”. Se não houverem problemas, a tarefa irá iniciar após executarmos o comando curl acima.
GitHub tem uma funcionalidade chamada de “Webhook”. Essa funcionalidade nada mais é do que uma solicitação de envio (POST) para algum endereço acessível (público) que aceita conexão HTTPS. Iremos usar o webhookrelay que é um serviço gratuito que faz redirecionamento de portas através de um endereço público para um endereço dentro de uma rede interna.
O tutorial de configuração de redirecionamento de portas pode ser visualizado no site oficial do serviço. Como descrito no tutorial oficial do webhookrelay, primeiro instalamos o CLI (Command line interface) na nossa máquina com o comando abaixo:
curl https://my.webhookrelay.com/webhookrelay/downloads/install-cli.sh | bash
Após fazer a instalação, criamos um novo “Bucket” na interface do serviço webhookrelay e definimos o endereço destino que é o endereço local da tarefa (job) que criamos (localhost:8080/job/ATMSonarqube/build?token=atmsonarqube). Após terminamos essa configuração, iremos receber um endereço público parecido com o abaixo:
https://rr6stfsa324incas1236p8rqy0.hooks.webhookrelay.com
O endereço acima será o endereço que iremos definir no webhook do github. No documento oficial do GitHub, os webhooks estão descritos detalhadamente. Se você tem um repositório, pode configurar o webhook no endereço abaixo:
https://github.com/$nomedousuario/$nomedorepositorio/settings/hooks
Após adicionar o endereço público que recebemos do webhookrelay no webhook do nosso repositório remoto no github, enviamos uma modificação. Se não houverem problemas, a tarefa (job) se iniciará sozinha.
Agora, toda vez que o repositório sofrer uma modificação ele irá notificar o jenkins que está operando na nossa rede interna.
Esse projeto foi um exemplo de integração contínua (CI). A integração contínua é uma porção do CI/CD que pertence ao DevOps. Essas tecnologias ajudam a automatizar sistemas e mitigar esforços humanos em relação a tarefas repetitivas. Conhecimentos em CI/CD tem sido um requerimento das empresas que contratam programadores. A automatização de tarefas é uma realidade que os desenvolvedores não devem fugir.
Postagens mais vistas
Os 5 principais componentes do computador são a unidade de controle, unidade aritmética e lógica, memória, dispositivo de entrada e dispositivo de saída.
A porta é um número de 16 bits que é adicionado no final do endereço IP, insinuando qual aplicativo está vinculado e atuando nessa porta.
Rede local de computadores (LAN) é um conjunto de computadores ou dispositivos conectados uns aos outros de forma isolada em um pequeno local.