Mauricio Magnani bio photo

Mauricio Magnani

A guy who loves technology and new challenges!

Email Twitter LinkedIn Github

JBoss Forge

JBoss Forge é um framework para criação de projetos baseado em padrões utilizando linha de comando. O JBoss Forge cria aplicações baseadas em Java EE em poucos instantes. A idéia é realmente facilitar a vida do desenvolvedor. Mais informações podem ser encontradas na página do projeto JBoss Forge.

O JBoss Forge será utilizado para criar uma pequena aplicação baseada em Maven onde serão aplicadas as práticas de DevOps. O JBoss Developer Studio já possui integração nativa com o JBoss Forge, facilitando assim a criação dessa aplicação. Ele é totalmente baseado no Eclipse e pode ser substituído por uma combinação de Eclipse + JBoss Tools.

Você pode baixar o JBoss Developer Studio gratuitamente na comunidade JBoss

O JBoss Forge cria aplicações baseadas em Maven. Ralize a instalação do Maven no próximo tópico.

Maven: Gerenciamento de Dependências

Apesar do Maven ser um framework voltado para área de desenvolvimento, é de grande importância que o time de operações tenha pelo menos um noção de qual a responsabilidade desse software.

o Maven é um framework que descreve a aplicação e suas dependências (bibliotecas). Além da descrição, é responsável pelo build das aplicações, compilando o código fonte, executando testes unitários, realizando o empacotamento, entre outros. Basicamente, ele funciona como um substituto do framework Ant e será amplamente utilizado pelo Jenkins.

A instalação consiste, basicamente do download do ZIP, seguido da descompactação. O instalador pode ser obtido em http://maven.apache.org.

Por fim, os comandos Maven serão sempre executados pelo intermédio de outras ferramentas como por exemplo Eclipse e Jenkins. Porém, caso haja a necessidade da execução manual em linha de comando, pode-se apontar a variável de ambiente PATH para a instalação do Maven.

Desenvolvendo com JBoss Forge

Utilizando o JBoss Developer Studio, navegue até Windows → Show View → Forge Console e inicie o Forge utilizando o botão start. Para criação de um novo projeto chamado judcon-brasil. execute o comando:

project-new --named judcon-brasil

Ps: JUDCon = JBoss Users and Developers Conference

Crie uma nova entidade JPA que representará o Palestrante do JUDCon:

jpa-new-entity --named Palestrante

O proximo passo é adicionar informações relacionadas ao Palestrante como: Bio, Nome, etc. Execute os comandos abaixo:

[Speaker.java]$ jpa-new-field --named nome
[Speaker.java]$ jpa-new-field --named sobrenome
[Speaker.java]$ jpa-new-field --named bio --length 2000
[Speaker.java]$ jpa-new-field --named twitter

Observe que a entidade Palestrante possui todas as informações necessárias e está pronta para uso:

@Entity
public class Palestrante implements Serializable {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "id", updatable = false, nullable = false)
  private Long id;
  @Version
  @Column(name = "version")
  private int version;

  @Column
  private String nome;

  @Column
  private String sobrenome;

  @Column(length = 2000)
  private String bio;

  @Column
  private String twitter;

Defina o JSF como framework padrão para a camada de apresentação:

[Speaker.java]$  faces-setup --facesVersion 2.2

O JBoss Forge, possui uma funcionalidade chamada scaffold, que gera todo o arcabouço inicial de uma aplicação MVC, como Camada de Apresentação (telas), Controladores, Dao, entre outras. Para isso, execute:

[Speaker.java]$  scaffold-generate --targets org.judcon.brasil.model.Palestrante
***SUCCESS*** CDI has been installed.
***SUCCESS*** EJB has been installed.
***SUCCESS*** Servlet API has been installed.
***SUCCESS*** JAX-RS has been installed.
***SUCCESS*** Scaffold was generated successfully.
[Speaker.java]$  build

Toda estrutura básica de uma aplicação web foi criada e está pronta para uso:

Continuous integration

Um desenvolvedor acaba de comitar uma mudança do sistema no repositório que contém a versão do código fonte, mas quando os outros desenvolvedores do projeto realizaram um checkout perceberam que o código não estava funcionando. Então enviaram um email relatando o problema, e depois de uma longa espera, a situação foi tratada e resolvida.

A prática de integração contínua tem como objetivo evitar situações como essa, tornando o processo de testes automatizado, garantindo assim qualidade no desenvolvimento das aplicações. Com o auxilio de ferramentas como: Jenkins e JUnit, é possível ter um ambiente de integração continua dinâmico e flexível.

Um dos pontos positivos dessa prática, é que o processo de configuração não é extenso, pode ser feito em poucos minutos sem uma preparação tão grande e não haverá a necessidade de se preocupar com uma nova configuração. As configurações só serão alteradas caso a necessidade mude, como inclusão ou execlusão de etapas.

A desvantagem dessa prática, é que as funcionalidades serão disponibilizadas para o time de QA, somente se todos os testes forem realizados com sucesso, o que pode gerar alguns atritos em relação ao time de negócios.

Publicando o Código Fonte no GitLab

Acesse novamente a URL http://gitlab e crie um novo grupo chamado devops:

Utilizando a funcionalidade New Project crie um novo projeto chamado conference com a visibilidadeprivate:

Clique no botão com o formato de uma chave de boca chamado Admin Area. Em seguida clique em New User:

Preencha as informações com os dados do desenvolvedor:

Observe que o GitLab iria enviar um Link para o email do usuário, mas como não foi configurado o SMTP, clique novamente em User, em seguida Edit no usuário para que a troca da senha seja realizada:

Navegue novamente até a página do projeto: [conference](http://gitlab/devops/conference/project_members e clique em Add Member, e Add users to project. Não esqueça de configurar o Project Access com a role Master:

Faça Logout e realize um novo login com o usuário mmagnani criado anteriormente. Clique em Profile SettingsSSH KeysAdd SSH Key . Adicione a chave criada Add Key no tópico “Preparando a Máquina do Desenvolvedor”:

A partir desse momento o desenvolvedor já está apto para publicar o projeto no GitLab.

Voltando para a máquina do desenvolvedor, navegue até o diretorio do projeto:

[mmagnani@localhost conference]$ pwd
/home/mmagnani/Development/PROJETOS/DevOps/conference

Inicialize o repositório do projeto Git:

[mmagnani@localhost conference]$ git init
Initialized empty Git repository in /home/mmagnani/Development/PROJETOS/DevOps/conference/.git/

Adicione todos os arquivos do projeto:

[mmagnani@localhost conference]$ git add .

Faça o primeiro commit:

[mmagnani@localhost conference]$ git commit -m "Primeiro Commit"

Adicione o repositório remoto que nesse caso está no GitLab:

[mmagnani@localhost conference]$ git remote add origin git@gitlab:devops/conference.git

Com o o código fonte para o repositório remoto:

[mmagnani@localhost conference]$ git push origin master
The authenticity of host 'gitlab (192.168.90.10)' can't be established.
ECDSA key fingerprint is 50:fd:30:b9:ed:67:07:d9:f6:d2:64:93:81:bd:db:1a.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'gitlab,192.168.90.10' (ECDSA) to the list of known hosts.
Counting objects: 101, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (81/81), done.
Writing objects: 100% (101/101), 1.02 MiB | 0 bytes/s, done.
Total 101 (delta 5), reused 0 (delta 0)
To git@gitlab:devops/conference.git
 * [new branch]      master -> master

Navegue até o GitLab http://gitlab/devops/conference/activity. O código fonte da aplicação já está disponível:

Automatizando o processo de Build com Jenkins

Jenkins é um servidor de integração contínua open source. É utilizado em larga escala, para execução de builds, testes e empacotamento das aplicações. O Jenkins possui recursos como: Groovy, API externa em JSON e XML, plugins, além de outros recursos que facilitam tarefas de manutenção, migração, gerenciamento das aplicações e integrações com outros sistemas.

Crie um novo playbook chamado jenkins.yml e deixe a configuração como abaixo:

- hosts: jenkins
  sudo: True
  user: vagrant
  tasks:
    - name: "Instala OpenJDK"
      yum: name=java-1.7.0-openjdk-devel state=latest

    - name: "Instala Git"
      yum: name=git state=latest

    - name: "Instala o wget e unzip"
      shell: sudo yum -y install wget unzip

    - name: "Download do Maven"
      get_url: url=http://mirror.nbtelecom.com.br/apache/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.zip dest=/tmp/apache-maven-3.3.3-bin.zip

    - name: "Descompacta o Maven em /opt"
      unarchive: src=/tmp/apache-maven-3.3.3-bin.zip dest=/opt copy=no

    - name: "Download do repositório Jenkins"
      shell: sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat-stable/jenkins.repo

    - name: "Cria um link simbólico para o Maven"
      shell: ln -s /opt/apache-maven-3.3.3 /opt/maven

    - name: "Importa a chave do repositório"
      shell: sudo rpm --import http://pkg.jenkins-ci.org/redhat-stable/jenkins-ci.org.key

    - name: "Instala Jenkins"
      shell: sudo yum -y install jenkins

    - name: "Habilita o jenkins"
      shell: sudo systemctl enable jenkins.service

    - name: "Inicia o jenkins"
      shell: sudo systemctl start jenkins.service

    - name: "Adiciona o IP do GitLab"
      lineinfile: 'dest=/etc/hosts line="192.168.90.10 gitlab"'

    - name: "Adiciona o IP do Nexus"
      lineinfile: 'dest=/etc/hosts line="192.168.90.30 nexus"'

    - name: "Chave SSH para Deploy no Gitlab"
      user: name=vagrant generate_ssh_key=yes

O arquivo VagrantFile também deve ser atualizado com a criação do novo servidor para o Jenkins e utilização do Playbook.

VAGRANTFILE_API_VERSION = "2"
ENV['VAGRANT_DEFAULT_PROVIDER'] = 'libvirt'

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  config.vm.box = "centos/7"

  config.vm.define :gitlab do |gitlab|
    gitlab.vm.hostname = "gitlab"
    gitlab.vm.network :private_network, :ip => "192.168.90.10"

    gitlab.vm.provision "ansible" do |ansible|
          ansible.playbook = "gitlab.yml"
          ansible.verbose = "vvv"
    end
 
    gitlab.vm.provider :libvirt do |domain|
      domain.memory = 1024
      domain.cpus = 2
    end

  end

  config.vm.define :jenkins do |jenkins|
    jenkins.vm.hostname = "jenkins"
    jenkins.vm.network :private_network, :ip => "192.168.90.20"

    jenkins.vm.provision "ansible" do |ansible|
          ansible.playbook = "jenkins.yml"
          ansible.verbose = "vvv"
    end
 
    jenkins.vm.provider :libvirt do |domain|
      domain.memory = 1024
      domain.cpus = 2
    end

  end

end

Para que o servidor e as configurações do Jenkins sejam criadas, basta executar o comando vagrant up:

[mmagnani@linux DevOps]$ vagrant up

Tudo ocorrendo conforme o esperado, navegue até a URL http://jenkins:8080 e a página inicial do Jenkins será exibida:

WebHook x Pooling

Instalando Plugins no Jenkins e Configurando GitLab WebHook

O Jenkins é um software bastante customizável e isso é alcançado através de plugins. Exitem plugins para as mais diversas finalidades como integração com GitLab, geração de relatório de testes, integraão com software APM (application performance management - Ex: Dynatrace), entre outros.

Como dito anteriormente, o Jenkins oferece integração nativa com Groovy. Para listar os plugins instalados atualmente, navegue até http://jenkins:8080/script e execute:

Observe o retorno:

Result

[Plugin:matrix-project, Plugin:javadoc, Plugin:credentials, Plugin:external-monitor-job, Plugin:mailer, Plugin:cvs, Plugin:antisamy-markup-formatter, Plugin:ant, Plugin:windows-slaves, Plugin:maven-plugin, Plugin:pam-auth, Plugin:translation, Plugin:ssh-credentials, Plugin:junit, Plugin:subversion, Plugin:matrix-auth, Plugin:ldap, Plugin:script-security, Plugin:ssh-slaves]

A instalação de plugin é feita de maneira simples. Acesse a opção Manage Jenkins localizada no menu lateral, em seguida Selecione Manage Plugins. Clique na aba Available. Selecione os seguintes plugins:

GitLab Logo Plugin
Gitlab Hook Plugin JaCoCo plugin

Em seguida, Install without restart e marque a opção Restart Jenkins when installation is complete and no jobs are running.

Acesse a opção Manage Jenkins localizada no menu lateral, clique em Configure System. Na opção Maven, deixe as configurações como abaixo e clique em Save.

Crie um novo JOB clicando em create new jobs e preencha o nome e o tipo do projeto:

Nome: Conference Tipo: Maven project

Em Source Code Management selecione Git e preencha a opção Repository URL com a URL do projeto Conference: git@gitlab:devops/conference.git . Em Branch Specifier (blank for 'any') configure como master. A opção Repository browser pode permanecer como Auto.

Clique em Save. A autenticação no repositório está falhando! Perceba que a autenticação do usuário jenkins no GitLab não existe e ainda não foi adicionada ao Jenkins.

Copie o valor da chave gerada na instalação do Jenkins:

[mmagnani@localhost DevOps]$ vagrant ssh jenkins
Last login: Wed Oct 21 13:54:17 2015 from 192.168.121.1
[vagrant@jenkins ~]$ cat /home/vagrant/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCvpeXzOxHO2LqPsAj+mvqd3BAaq7ep0PIBlT8iJQmEOOP2wp6G/hCkVZM3Kp42QYgmfIG8OUwfKTpazR3j/ftcB/LfNuDZJse1Xp0/B83B4he7MYHqJadwEgO8sRah0YUWK+yLNKRjDq+UEHuqqduOUFoeZNHxe7d9UDqTPG7Ei0Rjqo9gBiJuR3UobWPbqfXn8RGEhyF7/ydRtJsdghNxznnueuXIAtUpM+fu53xWF63LXjOtSpn+T0Nnj7YmvH4A2Wy+AC6Dnj/TWZ6dbPP3idOiej+0wmnWxzOTtdTO9cPzg79psH1aeJ0qq/JXHaPEKLU0aTVgZYdppihnZYrr ansible-generated on jenkins

Esse valor deve ser adicionado ao projeto no GitLab. Realize novamente login com usuário root . Clique no botão com o formato de uma chave de boca chamado Admin Area. Em seguida clique em New User e Preencha as informações com os dados do Jenkins:

Veja novamente que o GitLab iria enviar um link para o email do usuário, mas como não foi configurado o SMTP altere a senha manualmente. Clique em User e em seguida Edit no usuário para que a troca da senha seja realizada.

Agora navegue novamente até a página do projeto http://gitlab/devops/conference/project_members e clique em Add Member e Add users to project. Não esqueça de configurar o Project Access com a role Master

Faça Logout e realize um novo login com o usuário jenkins. Clique em Profile SettingsSSH KeysAdd SSH Key (o conteúdo da chave é /home/vagrant/.ssh/id_rsa.pub) . Adicione a chave criada Add Key gerada no passo anterior:

Retorne ao Jenkins e clique em Configure no JOB Conference: http://jenkins:8080/job/Conference/configure

Em Credentials clique em Add e preencha com as seguintes informações:

A Private Key se encontram em /home/vagrant/.ssh/id_rsa.

Clique em Save. A partir desse momento, o Jenkins já está apto para executar o primeiro Build da aplicação.

Implementando umas das práticas de DevOps, a integração continua deve ser executada automaticamente a cada mudança no repositório. Isso pode ser feito através de um mecanismo chamado Webhook. Webhooks permitem que sistemas externos recebam notificações de todos os eventos que ocorrem no sistema. Quando um evento acontece, o GitLab envia uma requisição HTTP POST para a URL configurada no webhook com as informações relativas ao evento. Ao receber a notificação, o Jenkins pode executar diversos procedimentos, com por exemplo o Build da aplicação.

Realize novamente login com usuário root . Clique no botão com o formato de uma chave de boca chamado Admin Area. Clique no projeto Conference, em seguida Edit → Web Hooks e preencha com a URL do Jenkins habilitada para esse fim utilizando o Plugin Gitlab WebHook.

http://jenkins:8080/gitlab/build_now

Para verificar o funcionamento, retorne para a máquina do desenvolvedor e crie um arquivo chamado README no diretório raiz do projeto. Realize os procedimentos para commit e push:

[mmagnani@localhost conference]$ echo "Testando WebHook" >> README
[mmagnani@localhost conference]$ git add README
[mmagnani@localhost conference]$ git commit -m "Testando WebHook" README
[mmagnani@localhost conference]$ git push origin master
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 288 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To git@gitlab:devops/conference.git
   2afad3a..ef385a4  master -> master

Retorne ao Jenkins e veja que o Build foi realizado automaticamente:

No servidor do Jenkins em /var/log/jenkins/jenkins.log, pode-se verificar o payload enviado pelo GitLab com o WebHook:

Oct 21, 2015 2:24:18 PM org.jruby.javasupport.JavaMethod invokeDirectWithExceptionHandling
INFO: matching projects:
   - Conference
Oct 21, 2015 2:24:18 PM org.jruby.javasupport.JavaMethod invokeDirectWithExceptionHandling
INFO: Conference scheduled for build
Oct 21, 2015 2:25:15 PM org.jruby.javasupport.JavaMethod invokeDirectWithExceptionHandling
INFO: gitlab web hook triggered for
   - repo url: git@gitlab:devops/conference.git
   - branch: master
   - with payload:
{
  "object_kind": "push",
  "before": "2afad3aa834d913ad949c0ca19be370db044c7ec",
  "after": "ef385a4b04fe1184bac9933448b44bd6c8b8e5c2",
  "ref": "refs/heads/master",
  "checkout_sha": "ef385a4b04fe1184bac9933448b44bd6c8b8e5c2",
  "message": null,
  "user_id": 4,
  "user_name": "Mauricio Magnani Jr",
  "user_email": "mmagnani@redhat.com",
  "project_id": 2,
  "repository": {
    "name": "conference",
    "url": "git@gitlab:devops/conference.git",
    "description": "Projeto destinado aos palestrantes do FISL16",
    "homepage": "http://gitlab/devops/conference",
    "git_http_url": "http://gitlab/devops/conference.git",
    "git_ssh_url": "git@gitlab:devops/conference.git",
    "visibility_level": 0
  },
  "commits": [
    {
      "id": "ef385a4b04fe1184bac9933448b44bd6c8b8e5c2",
      "message": "Testando WebHook\n",
      "timestamp": "2015-10-21T16:25:13-02:00",
      "url": "http://gitlab/devops/conference/commit/ef385a4b04fe1184bac9933448b44bd6c8b8e5c2",
      "author": {
        "name": "Mauricio Magnani Jr",
        "email": "mmagnani@redhat.com"
      }
    }
  ],
  "total_commits_count": 1
}
Oct 21, 2015 2:25:15 PM org.jruby.javasupport.JavaMethod invokeDirectWithExceptionHandling
INFO: matching projects:
   - Conference
Oct 21, 2015 2:25:15 PM org.jruby.javasupport.JavaMethod invokeDirectWithExceptionHandling
INFO: Conference scheduled for build
Oct 21, 2015 2:28:27 PM hudson.model.Run execute

Todo o processo foi realizado com sucesso utilizando o mecanismo de WebHook.