Este repositório é baseado na documentação: Build a Node.js and React app with npm
Parte 1
O repositório contém um aplicativo Node.js e React simples que gera uma página com o conteúdo "Bem-vindo ao React" e com um teste para verificar se o aplicativo é renderizado conforme esperado crianda nosso primeiro pipeline.
- Requisitos
- Bootstrap
- Desbloqueio
- Pipeline
- Sessões
- Running
- Test
- Delivery
- ProjetosMultiBranch
- MultiBranchPipeline
- MultiBranchDeploy
Parte 2
Integração com o Repo (GitHub Flow)
Utilizaremos a arquitetura baseada em containers para instanciar a primeira versão do Jenkins e demonstrar a configuração de um pipeline utilizando o plugin Blue Ocean, este laboratório é baseado na documentação Build a Node.js and React app with npm ;
1.1 Instalação do Docker CE: Para execução deste laboratório é necessário a instalação do serviço docker, existem versões para Windows, Linux e Mac, a documentação de apoio está disponível neste endereço: Install Docker Engine;
1.2 Instalação do Docker Compose, embora não seja um pré-requisito a infraestrutura de containers construida na documentação foi automatizada para este laboratório utilizando Overview of Docker Compose este recurso automatiza algumas etapas da configuração com a inicialização dos dcontainers e configuração de rede e volumes, por isso para seguir o passo-a-passo abaixo sua instalação é necessária e esta detalhada nesse documentação;
Você também pode executar este laboratório utilizando uma instância em núvem ou uma IDE como o Cloud9, opção utilizada neste cenário com base neste template e instruções de instalação;
2.1 Como executarmeos algumas alterações durante o laboratório é necessário que você execute um Fork deste repositório para sua conta local no GitHub, utilize um repositório aberto para evitar a configurações de credenciais de acesso no CI.
2.2 Acesse o servidor disponibilizado para o laboratório e caso ainda não esteja disponível execute um clone deste repositório, em seguida inicie o stack do Jenkins a partir da raiz do projeto
docker-compose up -d
Liberando o jenkins para uso;
3.1 Como esta é a primeira vez que o serviço pe inicializado será criada uma credencial provisória para acesso administrativo, essa informação será publicada ao final do processo de inicialização dos containers conforme abaixo.
Obs.: Se estiver utilizando um segundo terminal ou iniciou o container em background será possível recuperar as credenciais utilizando o comando abaixo:
docker logs jenkins-blueocean
3.1.1 A informação que aparece ao final da tela no formato de chave no campo com a descrição "Please use the following password to proceed to installation" será utilizada para desboquear o CI, para isso acesse a URL do servidor na porta 80 e coloque a chave obtida:
3.2 Depois de desbloquear o Jenkins, a página Customize Jenkins será exibida
3.3 Nesta página, clique em "Install suggested plugins."
O assistente de instalação mostra a progressão na instalação dos plug-ins sugeridos. Esse processo pode demorar alguns minutos.
3.4 Em seguida o Jenkins solicitará que você crie seu primeiro usuário administrador, especifique os detalhes nos respectivos campos, anote a senha utilizada e clique em Salvar e concluir.
3.5 Quando a página Jenkins estiver pronta aparecer, clique em "Start using Jenkins"
Criando o projeto e a integração
4.1 Crie seu projeto de pipeline no Jenkins, para isso na página "Welcome to Jenkins!" clique em criar "Create a Job"
4.2 No campo que surgir digite um nome para o seu novo projeto de Pipeline (por exemplo, simple-node-js-react-npm-app).
4.3 Em seguida logo abaixo escolha a opção "Pipeline", depois clique em OK no final da página.
4.4 Na parte superior da página clique na Guia Pipeline para rolar até a sessão de configuração do nosso Pipeline;
4.5 No campo "Definition", escolha a opção Pipeline script from SCM.
Esta opção instrui Jenkins a obter seu Pipeline do Source Control Management (SCM), que será seu repositório Git clonado localmente, essa será nossa primeira ação prática rumo a integração contínua;
4.6 No campo SCM, escolha Git.
4.7 No campo URL do Repositório, especifique o repositório clonado, por exemplo: https://github.com/fiapdevops/pipelines.git
Importante: Tome o cuidado de utilizar o seu repositório para que tenha o acesso necessário para fazer alterações no futuro envolvendo credenciais para execução de webhooks;
4.8 Ao final da tela no campo "Script Path" utilize a path pipelines/Jenkinsfile indicando o Jenkinsfile dentro do diretório pipelines;
4.8 Clique em Salvar para salvar seu novo Pipeline. Agora você está pronto para começar a criar seu Jenkinsfile;
Vantagens no uso de um arquivo declarativo como o Jenkinsfile
- Utilizando este método é possível estabelecer estratégias de Code Review para o próprio Pipeline de Integração Contínua;
- Também é possível auditar as etapas e literalmente "rastrear" o fluxo percorrido pelo produto sendo entregue via Pipeline;
- Também conseguiremos um "Single source of truth" para o Pipeline, ou seja, ele poderá ser visualizado e editado por vários membros do projeto.
No Jenkins estes pipelines podem ser escritos utilizando uma linguagem declarativa ou a linguagem de programação Groovy;
Criando o primeiro pipeline
O conteúdo base necessário para o nosso primeiro pipeline está na raiz do repositório no arquivo JenkinsFile conforme abaixo:
pipeline {
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000'
}
}
environment {
CI = 'true'
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
}
}
Este fluxo possui um único stage chamado Build, e um único agente chamado docker ambos os conceitos explicados abaixo:
A composição bruta de um pipeline em Jenkins
5.1 Um pipeline declarativo em Jenkins será sempre dividido em sessões, cada sessão possui uma função dentro do fluxo do pipeline.
5.2 A sessão "agent" especifica onde o Pipeline, ou um estágio específico dele será executado, essa seção deve ser obrigatoriamente declarada ao menos uma vez no nível superior de dentro do bloco de pipeline, também é possível declarar em niveis inferiores alternando entre ambientes mas este uso é opicional.
Neste exemplo para a sessão agent utilizamos o tipo Docker o que provisionará um container que será o hospedeiro do ambiente responsável por executar a etapa seguinte, essa tática tem sido muito utilizada por desenvolvedores a fim de isolar dependências dentro do Pipeline em relação ao servidor hospedando a aplicação que será construída.
5.3 A sessão "stage" contém o ponto mais importante deste estudo, o core do pipeline, uma sequência de uma ou mais diretivas com as funções que constroem os estágios é onde a maior parte do "trabalho" descrito por um Pipeline será localizado a partir de ações como compilar, testar e implementar, etc.
Execute o primeiro pipeline do laboratório
6.1 Após verificarmos a esturtura por trás do pipeline faremos a primeira execução utilizando o plugin blue ocean, para isso volte para Jenkins novamente, faça login se necessário e clique em "Open Blue Ocean" no painél à esquerda para acessar a interface do plugin., nesta interface você provavelmente verá uma mensagem "This job has not been run", clique em "Run":
6.2 Em seguida, clique rapidamente no link "OPEN" que aparece brevemente no canto inferior direito para ver Jenkins construindo seu projeto:
6.3 Se não foi possível clicar no link, clique na linha que aparece interface principal do Blue Ocean para acessar esse recurso.
O Blue Ocean é um plugin extremamente popular que trás como proposta repensar a experiência do usuário no CI. Ele basicamente projeta o Pipeline e cria um modelo visual para os estágios, o que reduz a desordem e aumenta a clareza para todos os membros da equipe, vale apena uma lida na documentação do projeto para os interessados em maiores detalhes;
jenkins.io: What is Blue Ocean?
6.4 Ao final da execução a primeira versão do pipeline estará completa:
"Adicionando uma etapa de testes"
7.1 Utilizando uma versão local ou o editor ntivo do GitHub na internet abra o arquivo jenkinsfile para edição;
7.2 Em seguida copie e cole o bloco abaixo no seu Pipeline imediatamente sob a seção "agent" do arquivo Jenkinsfile:
environment {
CI = 'true'
}
7.3 Além disso, adicione o seguinte bloco imediatamente após o estágio Build:
stage('Test') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/test.sh'
}
}
7.4 O Conteúdo final do pipeline ficará assim:
pipeline {
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000'
}
}
environment {
CI = 'true'
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/test.sh'
}
}
}
}
"Adicionando uma etapa final para entrega"
8.1 Abra novamente o arquivo Jenkinsfile para edição e adicione um novo estágio:
stage('Deliver') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/deliver.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
Esta etapa será responsável por acionar um script de entrega da aplicação em um ambiente temporário.
O input ao final é naturalmente opicional e adiciona apenas uma etapa de pausa para facilitar a verificação do fluxo antes que o pipeline seja totalmente finalizado e apresenta uma das várias possibilidades para integrações em casos onde o objetivo é o delivery contínuo com alguma decisão manual antes ou depois da entrega;
8.2 Verifique o modelo final do Jenkinsfile:
pipeline {
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000'
}
}
environment {
CI = 'true'
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/test.sh'
}
}
stage('Deliver') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/deliver.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
}
}
8.3 Durante a entrega, enquanto não clicarmos na opção Proceed a página ficará acessível na URL do CI na porta 3000;
Nesta etapa ampliaremos a configuração do projeto para um modelo com multi branchs no processo de desenvolvimento;
Trabalhar com multiplas brancs permite a implantação de fluxos mais complexos baseados em workflows como GitFlow e GitlabFlow;
9.3 A partir da interface do Jenkins clique em 'Open Blue Ocean' no painel a esquerda;
9.4 No menu no topo da página clique em 'Pipelines', e no menu logo abaixo clique em 'New Pipeline' para iniciar o assistente;
9.5 Na opção 'Where do you store your code?' selecione 'Git' (Não utilize a opção GitHub);
9.6 No campo 'Repository URL', especifique o repositório remoto na sua conta Git, mantenha os campos Username e Password em branco,
9.7 Clique em 'Create Pipeline' ao finalizar o processo;
9.8 Por padrão ao criar pipelines utilizando o blue ocean ele automaticamente interpreta que o modelo de implantação pode ser executado com multiplas branchs, isso ocorrerá a partir da existência de novas branchs com arquivos de Jenkinsfile;
Se for necessário excluir uma branch do fluxo basta que ela não possua um arquivo Jenkinsfile ou que ele seja removido, utilizando recursos como o arquivo .gitignore, Se ao criar um projeto de Pipeline no Blue Ocean o Jenkinsfile não existir mas for adicionado posteriormente basta utilizar o recurso 'Scan Multibranch Pipeline Now' na home do projeto;
"Adicione etapas de entrega e implantação do seu Pipeline"
10.1 Usando a sua IDE ou a interface do GitHub edite o seu arquivo Jenkinsfile na branch main alterando o stage de execução do pipeline:
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000 -p 5000:5000'
}
}
environment {
CI = 'true'
}
Esta alteração consiste em adicionar a porta de produção do node no fluxo (Internamente é a porta 5000) que será utilizada nas etapas a seguir;
10.2 Substitua o antigo stage Deliver pelo modelo abaixo:
stage('Deliver for development') {
when {
branch 'development'
}
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/deliver.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
No modelo de multiplas branchs a alteração permitirá criar um estágio cuja execução é condicionada a commits na branch development;
Se o valor da condição definida na função when no início do stage corresponder ao nome da branch na qual o Jenkins está executando a compilação, o estágio declarado será executado, essa abordagem permite estruturar tarefas distintas para o ambiente de desenvolvimento e de produção.
10.3 A versão atual do seu arquivo de pipeline possuirá um layout similar ao modelo abaixo:
pipeline {
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000 -p 5000:5000'
}
}
environment {
CI = 'true'
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/test.sh'
}
}
stage('Deliver for development') {
when {
branch 'development'
}
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/deliver.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
}
}
10.4 Agora crie uma nova branch de desenvolvimento para que possamos atuar com multiplas branchs e testar a primeira condição:
Na execução pelo terminal:
git branch development
10.5 Para que o plugin identifique a nova branch volte a página principal do CI, clique sobre o Job criado e no painel no canto esquerdo da tela escolha a opção '"Scan Multibranch Pipeline Now"'
É possível confirmar se o CI identificou a nova branch verificando o log no botão abaixo da opção utilizada:
10.6 Após a alteração volte ao Blue Ocean e execute um novo Job na branch main, para isso clique em 'Branchs' no canto superior direito para acessar a lista das branchs do seu projeto de Pipeline, existirá um job em execução relativo a branch development.
10.5 Para testar a configuração inicie o job a partir da branch main clicando na opção 'Run' na linha da branch main no Pipeline;
"Etapa final com o deploy da aplicação"
Será necessário adicionar o novo script para deploy em produção no diretório jenkins/scripts no seu repositório Git:
11.1 Crie o arquivo jenkins/scripts/deployment.sh com o conteúdo abaixo:
#!/usr/bin/env sh
set -x
npm run build
set +x
echo 'The following "npm" command downloads and installs the npm serve module'
set -x
npm install serve
set +x
echo 'The "serve" command has a trailing ampersand so that the command runs'
echo 'as a background process (i.e. asynchronously). Otherwise, this command'
echo 'can pause running builds of CI/CD applications indefinitely.'
set -x
./node_modules/serve/bin/serve.js -c 0 -s build &
sleep 1
echo $! > .pidfile
set +x
echo 'Now...'
echo 'Visit http://localhost:5000 to see your Node.js/React application in action.'
echo '(This is why you specified the "args ''-p 5000:5000''" parameter)'
11.2 Além da alteração anterior adicione um segundo estágio que será utilizado para a entrega em produção e configure o uso da porta 5000 para expor a app, essa configuração será aplicada a branch main e em seguida adicionaremos o mesmo conteúdo nas branchs development e production
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000 -p 5000:5000'
}
}
...
stage('Deploy for production') {
when {
branch 'production'
}
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/deployment.sh'
input message: 'Finished with your production version? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
11.3 A versão final do seu arquivo de pipeline possuirá um layout similar ao modelo abaixo:
pipeline {
agent {
docker {
image 'node:12-alpine'
args '-p 3000:3000 -p 5000:5000'
}
}
environment {
CI = 'true'
}
stages {
stage('Build') {
steps {
sh 'npm install'
}
}
stage('Test') {
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/test.sh'
}
}
stage('Deliver for development') {
when {
branch 'development'
}
steps {
sh 'chmod +x ./jenkins/scripts'
sh './jenkins/scripts/deliver.sh'
input message: 'Finished using the web site? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
stage('Deploy for production') {
when {
branch 'production'
}
steps {
sh 'chmod -R +x ./jenkins/scripts'
sh './jenkins/scripts/deployment.sh'
input message: 'Finished with your production version? (Click "Proceed" to continue)'
sh './jenkins/scripts/kill.sh'
}
}
}
}
11.4 Voltando ao repositório Git faça atualize os arquivos Jenkinfile de acordo com as mudanças que executamos no arquivo disponível no repositório principal.
git checkout main
git checkout -b development
git push
11.5 Testando o modelo completo, utilize o botão localizado a esquerda da opção logout menu no canto superior direito da tela para voltar a interface do Jenkins, em seguida clique sobre o Pipeline e clique no botão Scan Multibranch Pipeline Now.
Em segundos o CI identificará a branch development e iniciará um novo Job.
Como você está construindo a aplicação em uma branch diferente, a etapa de instalação do npm exigirá alguns minutos para que o npm faça o download das dependências necessárias para executar o Node.js e React;
11.6 Ao final do processo acesse a página do CI na porta 3000 para verificar a aplicação Node rodando em modo de desenvolvimento e finalize a aplicação pleo CI clicando na opção "Proceed";
11.7 Finalmente faça um novo teste iniciando o Job a partir da branch "Production";
profhelder.pereira@fiap.com.br
Free Software, Hell Yeah!