O modelo DevOps (união das palavras development e operations) combina filosofia de trabalho, ferramentas e práticas que agilizam o processo de entregas e implantação de softwares. Todo o fluxo ocorre em cima de uma estrutura conhecida como Esteira DevOps ou CI/CD (continuous integration / continuous delivery) pipeline.


*Figura 1 - Etapas da Esteira DevOps


Nesse tutorial veremos como configurar o Jenkins para obter um projeto criado no Cronapp e executar as seguintes etapas do pipeline:

  1. Obter o código do repositório GitHub,
  2. Compilar o projeto,
  3. Criar uma imagem Docker,
  4. Salvar essa imagem no Docker Hub.

Pré-requisitos

Esse tutorial não prevê os passos iniciais para instalação e configuração do Jenkins e Docker. Porém, para executar o Jenkins, será necessário instalar:

  1. Java SDK 11,
  2. Tomcat 9,
  3. Maven,
  4. Configurar as variáveis de ambiente:
  5. Git,
  6. Docker,
  7. Jenkins
    Clique aqui para mais detalhes sobre a instalação do Jenkins e como vincular o Docker ao Jenkins.


  • No Cronapp, o modo Modo Avançado deve estar habilitado;
  • Usaremos como repositório:
    • GitHub: para o repositório de código;
    • Docker Hub: para o repositório de imagem.


Caso pretenda usar o GitHub e Docker Hub como seus repositórios de código e imagens respectivamente, certifique-se de que os dados sensíveis não sejam disponibilizados em repositórios públicos. 

Ao criar repositório nesses sistemas, o padrão é estarem configurados como públicos.

Para esse tutorial utilizamos uma imagem Docker com o Jenkins, sendo executado no Linux.

Pipeline

No arquivo Jenkinsfile encontramos uma estrutura que utiliza o Pipeline, uma linguagem de domínio específico (DSL) com base na linguagem de programação Groovy. É utilizada pelo Jenkins para criar e personalizar os jobs.

Abaixo temos o conteúdo do Jenkinsfile que encontramos ao criar um projeto no Cronapp. 

Arquivo Jenkinsfile
pipeline {
	agent any
	parameters{
		choice(choices: ['true', 'false'], description: 'Selecione se quer usar conexões de banco e parâmetros dentro do conteiner.', name: 'CRONAPP_USE_CONTEXT')
		choice(choices: ['DEV', 'PROD'], description: 'Selecione o perfil do banco de dados (TIER).', name: 'CRONAPP_TIER')
		choice(choices: ['true', 'false'], description: 'Incluir projeto mobile.', name: 'CRONAPP_MOBILE_APP')
		string(defaultValue: 'https://index.docker.io/v1/', description: 'URL do Registry (padrão é o docker hub).', name: 'CRONAPP_DOCKER_REGISTRY', trim: false)
		string(defaultValue: 'INFO_SEU_USUARIO/NOMEDAIMAGEM', description: 'Informe o nome de sua imagem (se for registry privado, informe o caminho completo).', name: 'CRONAPP_DOCKER_IMAGE_NAME', trim: false)
		string(defaultValue: 'INFO_ID_CREDENCIAL_DOCKERHUB', description: 'Informe a credencial (secret) usada para acesso ao registry.', name: 'CRONAPP_DOCKERHUB_ACCESS', trim: false)
		string(defaultValue: 'INFO_URL_REPO_GIT_HTTPS', description: 'Informe o endereço HTTPS do repositório Git.', name: 'CRONAPP_GIT_URL', trim: false)
		string(defaultValue: 'INFO_ID_CREDENCIAL_GITHUB', description: 'Informe a credencial (secret) usada para acesso ao reposotório Git.', name: 'CRONAPP_GIT_USERPASS', trim: false)
		
	}
	stages {
		stage('Git Clone') {
			steps {
				checkout([$class: 'GitSCM', branches: [[name: '${CRONAPP_TAG_VERSION}']], doGenerateSubmoduleConfigurations: false, extensions: [[$class: 'CloneOption', noTags: false, reference: '', shallow: false]], submoduleCfg: [], userRemoteConfigs: [[credentialsId: "${CRONAPP_GIT_USERPASS}", url: "${CRONAPP_GIT_URL}"]]])
			}
		}
		stage('Maven and Docker Build') {
			steps {
				sh  '''
					docker build -t ${CRONAPP_DOCKER_IMAGE_NAME}:${CRONAPP_TAG_VERSION}-${CRONAPP_TIER} --build-arg TIER=${CRONAPP_TIER} --build-arg CONTEXT_USE=${CRONAPP_USE_CONTEXT} --build-arg MOBILE_APP=${CRONAPP_MOBILE_APP} .
				'''
			}
		}
		stage('Docker Push') {
			steps {
				withDockerRegistry(credentialsId: "${CRONAPP_DOCKERHUB_ACCESS}", url: "${CRONAPP_DOCKER_REGISTRY}") {
					sh  '''
						docker push ${CRONAPP_DOCKER_IMAGE_NAME}:${CRONAPP_TAG_VERSION}-${CRONAPP_TIER}
					'''
				}
			}
		}
		stage('Docker Clean') {
			steps {
				sh  '''
					docker image prune -f
				'''
			}
		}
	}
} 


Declarações usadas:

  • agent any: o Jenkins permite distribuir a carga de compilação para diferentes nós, porém, o "agent any" define que qualquer nó disponível pode realizar essa ação.
  • parameters: parâmetros passados para o Jenkins com informações dos repositórios e configurações de banco de dados. Acesse o tópico Executar pipeline para mais detalhes.
  • stages: define os passos do pipeline do Jenkins:
    • Git Clone: clona o projeto do repositório de código informado;
    • Maven and Docker Build: faz o build do projeto e gera uma imagem Docker com base nas configurações do Dockerfile do projeto;
    • Docker Push: envia a imagem recém-criada para o Docker Hub;
    • Docker Clean: apaga todas as imagens sem tags, incluindo as que foram geradas no build.

Passos

Para os passos abaixo é necessário acessar a aplicação do Jenkins em seu navegador.

Configuração inicial

Esse tópico apresentará os passos iniciais ao acessar o Jenkins pela primeira vez, caso já possua um Jenkins configurado, pule para o tópico Criar credenciais.

A primeira coisa solicitada pelo Jenkins é a Senha de administrador, essa senha é exibida no log de instalação e também está em um arquivo no diretório apontado na própria tela (destaque 1 da figura abaixo). Informe a senha e clique em Continuar.


Figura 2 - Janela ao executar o Jenkins pela primeira vez


Selecione a opção Install suggested plugins para que o Jenkins adicione automaticamente os plugins mais comuns.


Figura 2.1 - Opção para adicionar os plugins mais utilizados


Aguarde o Jenkins instalar os plugins (Figura 2.2).


Figura 2.2 - Instalação dos plugins Jenkins


Após a instalação dos plugins será exibido uma janela para cadastrar um usuário administrador, informe os campos solicitados e clique em Save and Continue.


Figura 2.3 - Criação do primeiro usuário administrador


Em seguida o Jenkins exibirá o domínio e porta em que estará rodando, Clique em Save and Finish.


Figura 2.4 - Criação do primeiro usuário administrador


No último passo o Jenkins apenas informa que a instalação está completa, clique em Start using Jenkins para ser direcionado até a página de Bem-vindo da aplicação Jenkins (Figura 2.5).


Figura 2.5 - Página inicial da aplicação Jenkins

Criar credenciais

Vamos usar o Jenkins para armazenar as credenciais de acesso do GitHub e Docker Hub, impedindo que esses dados fiquem expostos.

No link Painel de controle (canto superior esquerdo), posicione o cursor do mouse até exibir o ícone do menu e clique para exibir o menu (destaque 1 da figura 3), acesse Gerenciar Jenkins > Manager Credentials para abrir a página de Credentials. Na lista Stores scoped to Jenkins, posicione o cursor do mouse em (global) (coluna Domains) até exibir o ícone do menu e clique para exibir as opções (destaque 2 na figura 2.1), selecione a opção Add Credentials.


Figura 3 - Acesso ao gerenciador de Credenciais do Jenkins


Alimente os campos com os seus dados do Github e clique no botão Create para cadastrar, após isso, clique em Credentials no breadcrumbs (destaque 1 da figura 3.1) para retornar a tela do gerenciar de credenciais (Figura 3) e criar um nova credencial, dessa vez para preencher com os dados do Dockerhub.


Figura 3.1 - Acesso ao gerenciador de Credenciais do Jenkins

GitHub

  • Kind: deixe a opção padrão Username with password.
    • Scope: selecione a opção Global.
    • Username do GitHub.
    • Password: informe o token gerado a partir da sua conta do Github.
    • ID: para facilitar a identificação, sugerimos adicionar o nome do projeto e serviço da credencial (ex.: "nome_do_projeto-github").
    • Description: adicione uma descrição própria ou informe o mesmo valor do ID (ex.: "Credencial do Github.").


Docker Hub

  • Kind: deixe a opção padrão Username with password.
    • Scope: selecione a opção Global.
    • Username do Docker Hub.
    • Password do Docker Hub.
    • ID: para facilitar a identificação, sugerimos adicionar o nome do projeto e serviço da credencial (ex.: "nome_do_projeto-dockerhub").
    • Description: adicione uma descrição própria ou informe o mesmo valor do ID (ex.: "Credencial do Dockerhub.").


Anote os ID's utilizados nas 2 credenciais, usaremos eles ao executar o pipeline.


Ao final, teremos 2 credenciais globais (Figura 3.2).


Figura 3.2 - Após finalizar o cadastro do Github e Dockerhub

Adicionar plugins

O próximo passo será a instalação do Plugin Docker Pipeline


Figura 4 - Instalação do plugin Docker pipeline


  1. No link Painel de controle (canto superior esquerdo), posicione o cursor do mouse até exibir o ícone do menu e clique para exibir o menu (destaque 1 da figura 4), acesse Gerenciar Jenkins > Gerenciar extensões para abrir a página de Gerenciador de extensões.
  2. Selecione a aba Disponíveis.
  3. Digite o nome do plugin: Docker pipeline
  4. Marque a caixa de seleção do plugin.
  5. Clique em Baixar agora e instalar após o reinício.


O Jenkins mudará para a página de instalação do plugin, aguarde esse procedimento e, em seguida, logue novamente na aplicação.

Criar o Job

No link Painel de controle (canto superior esquerdo), posicione o cursor do mouse até exibir o ícone do menu e clique para exibir o menu (destaque 1 da figura 5), acesse Nova tarefa para abrir a página inicial de configuração. Informe um nome para o job (destaque 2), selecione a opção Pipeline (3) e clique em Tudo certo (4)


Figura 4.1 - Criando um Job do tipo Pipeline

Parâmetro da Branch

Antigamente recomendávamos o uso de um plugin para listar todas as Branchs e Versões tags do Git do projeto, permitindo apenas selecionar a versão do projeto que iria ser utilizada no pipeline. Porém, esse plugin deixou de ser mantido e apresenta falha de segurança, assim, vamos criar um parâmetro para informar manualmente a branch ou versão tag que será utilizada.

Marque a opção Esta construção é parametrizada e na caixa de seleção exibida, selecione a opção Parâmetro de texto (Figura 5),


Figura 5 - Novo parâmetro do tipo texto


Será exibido uma área com alguns campos, preencha como informado abaixo.


Figura 5.1 - Configuração do parâmetro CRONAPP_TAG_VERSION


  • Nome: nome do parâmetro utilizado no arquivo Jenkinsfile, informe exatamente o valor "CRONAPP_TAG_VERSION".
  • Valor padrão: nome da branch ou tag version que será utilizado, esse valor poderá ser alterado depois, ao executar o pipeline.
  • Descrição do campo.

Script do pipeline

Ainda nessa página, desça até a área de configuração do Pipeline e preencha os campos abaixo. Nessa área, os campos identados serão exibidos a medida que os campos superiores forem selecionados.


Figura 6 - Configuração do sistema de controle de código do pipeline


  • Definition: selecione a opção "Pipeline script from SCM".
    • SCM: selecione a opção "Git".
      • Repositories / Repository URL: endereço Git (https) do seu projeto.
      • Repositories / Credentials: selecione a credencial de acesso Git criado no primeiro passo desse tutorial.
    • Script Path: nesse campo deve ser informado o endereço do arquivo Jenkinsfile dentro do projeto. Como esse arquivo fica na pasta raiz, informe apenas o nome do arquivo “Jenkinsfile”.
    • Demais campos: deixe a configuração padrão do Jenkins nos outros campos.


Finalizada as configurações, clique em Salvar.

Obter demais Parâmetros do pipeline

Para executar o pipeline são necessários outros parâmetros além do que cadastramos no tópico Parâmetro da Branch. Esses parâmetros podem ser obtidos automaticamente a partir do arquivo Jenkinsfile do projeto. Assim, será necessário executar o pipeline pela primeira vez, durante a execução, o Jenkins irá obter os parâmetros definidos e apresentará uma falha, já que os parâmetros ainda não foram preenchidos.

Na página do Job criado, clique em Construir com parâmetros (destaque 1 da figura 7) e na tela de Construção será exibido apenas o parâmetro criado anteriormente: CRONAPP_TAG_VERSION. Nesse momento não é necessário informar um valor correto neste campo, clique em Construir (2).


Figura 7 - Configuração do sistema de controle de código do pipeline


Após o erro de execução (figura 7.1), o Jenkins já possui todos os parâmetros necessários.


Figura 7.1 - Erro gerado na primeira execução do pipeline

Executar o pipeline

Clique novamente em Construir com parâmetros (destaque 1 da figura 8) para voltar a tela de execução do pipeline. Verifique que agora são exibidos todos os parâmetros contidos no arquivo Jenkinsfile, mais o parâmetro "CRONAPP_TAG_VERSION" que incluímos no tópico Parâmetro da Branch

Configure os campos como descritos abaixo.


Figura 8 - Tela de execução do Pipeline


  • CRONAPP_USE_CONTEXT: permite incluir no pacote final do projeto as configurações usadas no perfil do banco de dados (arquivo context.xml). Para mais informações, acesse o tópico "Exportando war via comando (High-code)" em Importar e exportar projetos.

    Fique atento ao definir essa opção como "true", isso fará com que as configurações de banco de dados sejam armazenadas na imagem, gerando alto risco ao disponibilizar publicamente essa imagem.

    Recomendamos alterar essa opção para "false", porém será necessário usar recursos do orquestrador Docker, onde é possível informar as conexões de banco de dados necessárias ao contêiner/aplicação por meio de secrets.

    • true: adiciona as configurações do perfil de banco de dados;
    • false: não adiciona as configurações do perfil de banco de dados.

  • CRONAPP_TIER: informe qual perfil de banco de dados será usado.
    • DEV: desenvolvimento;
    • PROD: produção.
  • CRONAPP_MOBILE_APP: permite incluir na raiz do pacote um diretório (mobileapp/) com a aplicação mobile do projeto.
    • true: inclui a aplicação mobile;
    • false: não inclui a aplicação mobile.
  • CRONAPP_DOCKER_REGISTRY: endereço do Registry usado da imagem, o valor padrão é o Dockerhub.
  • CRONAPP_DOCKER_IMAGE_NAME: nome da <conta>/<repositório> da imagem. 
  • CRONAPP_DOCKERHUB_ACCESS: identificador da credencial de acesso ao Docker Hub.
  • CRONAPP_GIT_URL: endereço (HTTPS) do repositório Git. 
  • CRONAPP_GIT_USERPASS: identificador da credencial de acesso ao GitHub,
  • CRONAPP_TAG_VERSION: tag version ou branch que será usada na construção.


Clique em Construir para iniciar o processo.

Na página Stage View é possível acompanhar o andamento de cada etapa do processo (destaque 1 da figura 8.1). O tempo de execução do pipeline pode variar bastante, mas em média costuma levar de 8 a 20min, sendo influenciado por fatores como velocidade da internet e o hardware do equipamento que executa o Jenkins.

Para reduzir esse tempo, use métodos para adicionar seu .m2/repository no Dockerfile, evitando a necessidade do download das dependências a cada execução do job, ou realize o build da aplicação fora do Dockerfile.


Figura 8.1 - Job do pipeline em execução


Em caso de falha no processo, acesse o Console Output (2 da figura 8.1) e verifique o que causou o erro.

Resultado

Finalizado a execução do pipeline, acesse o Docker Hub para verificar a imagem criada do seu projeto.


Figura 9 - Imagem Docker gerada através do pipeline deste tutorial

Problemas e soluções

Abaixo descrevemos alguns problemas que podem ocorrer durante a execução do pipeline e como solucioná-los.

Antes de tudo, é preciso ter ciência que o ambiente que for executar o Jenkins necessita do Java SDK 11, Tomcat 9, Git, Maven, Docker e de suas respectivas variáveis de ambiente configuradas. Clique aqui para mais detalhes sobre a instalação do Jenkins.


ProblemaSugestão de solução

Erro java.io.IOException: CreateProcess error=2 Caused: java.io.IOException: Cannot run program "nohup".

Dependendo da forma como de como o Git foi instalado, talvez seja necessário alterar as configurações de variáveis de ambiente. clique aqui para mais detalhes.

Erro "In the default daemon configuration on Windows, the docker client must be run elevated to connect. This error may also indicate that the docker daemon is not running."

Verifique se o cliente Docker está aberto e em execução.

Erro: "java.lang.NoSuchMethodError: No such DSL method 'withDockerRegistry' found among steps [archive, bat, build, catchError, ...]"

Verifique se o plugin Docker Pipeline está instalado no Jenkins.

* A Figura 1 foi criada por Kharnagy e está sob licença CC BY-SA 4.0.


  • Sem rótulos