1 - Introdução

editar

Propósito

editar

Este plano de gerência de configuração de software tem como objetivo especificar as práticas e ferramentas que serão utilizadas no processo de manutenção do software enem amigo. O software em questão foi desenvolvido por estudantes da Universidade de Brasília no segundo semestre de 2015 e sua proposta é atuar como uma ferramenta de auxílio aos estudos para o Exame Nacional do Ensino Médio (ENEM).

Escopo

editar

O planejamento de mudanças tem como proposta adicionar uma ferramenta de automatização de integração continua ao projeto, automatizar sua implantação, produção de pacotes .deb para instalação em ambientes debian e evolução do repositório oficial visando atrair colaboradores.

Repositório do Projeto

editar

O repositório do projeto está disponível em https://github.com/pedrodelyra/enem-amigo.

2 - Gerência de Configuração de Software

editar

Organização, Responsabilidades e Interfaces

editar
Papel Responsabilidade Responsável
Gestor de configuração do projeto Acompanha as alterações dos itens de configuração. Renata Soares
Gestor de ferramentas de gerência de configuração de software Mantém a infraestrutura necessária para a gerência de configuração. Pedro de Lyra e Renata Soares.
Gestor de configuração de software Aprova e gerencia as atividades. Pedro de Lyra
Auditor de configuração de software Realiza as auditorias. Pedro de Lyra e Renata Soares.
Desenvolvedores Desenvolvem os itens de configuração que serão gerenciados. Pedro de Lyra e Renata Soares.

Ferramentas, Ambiente e Infraestrutura

editar

Git

O git será o sistema de controle de versão utilizado para gerenciar as versões do projeto.

Github

O Github sera utilizado para hospedar o repositório oficial do projeto.

Travis CI

O Travis CI é um ambiente web destinado à automatização da integração contínua de projetos de software. Ele será a ferramenta escolhida para adicionar integração contínua ao projeto.

Vagrant

O Vagrant é uma ferramenta utilizada para realizar a automatização da construção de ambientes de desenvolvimento.

Hospedagem

O Digital Ocean é um sistema que fornece diversos serviços de hospedagem e será utilizado para criação do servidor que hospedará a aplicação após sua implantação.

Capistrano

O Capistrano será a ferramenta utilizada para automatização do deploy do projeto.

Shell Script

O Shell Script será utilizado para produção de scripts que automatizem determinadas partes do projeto que não necessitem de ferramentas externas além de um interpretador de linhas de comandos.

Chef

O chef é uma ferramenta para automatizar a infraestrutura, aplicações e todo o fluxo de trabalho DevOps.

Dh_make e debuild

Estas ferramentas serão usadas no empacotamento debian do projeto.

3 - Gerência de Configuração de Programa

editar

Identificação da Configuração

editar

A baseline que será gerenciada de acordo com o plano é a branch master do repositório que consiste em uma versao entregável do projeto.

Configuração e Controle de Mudança

editar

Os recursos adicionados pelo gerenciamento de configuração serão experimentados em uma versão independente do projeto mantida em uma branch específica.

Relato do Status de Configuração

editar

O status de configuração será registrado no repositório através da ferramenta de controle de versão, contendo todas as alterações realizadas, a descrição, o autor, a data e horário de cada uma delas.

4 - Cronograma

editar
Data Entrega
27/04/2016 Plano de gerência de software
04/05/2016 Evolução do repositório oficial
11/05/2016 Adicionar integração contínua
25/05/2016 Realizar deploy
08/06/2016 Automatizar deploy
22/06/2016 Realizar empacotamento Debian

5 - Resultados

editar

Automatização da Integração Contínua com Travis CI

editar

A ferramenta Travis CI foi selecionada para realizar a automatização da integração contínua do projeto. Seu uso é simples, rápido e fácil. Em primeiro lugar, é necessário sincronizar as contas do Github e do Travis CI. Em seguida, basta selecionar o repositório que deseja ser monitorado pelo Travis e adicionar um arquivo de configuração no diretório raíz do projeto, denominado ".travis.yml". Este arquivo contém algumas especificações sobre o projeto, as branches que serão rastreadas pelo Travis e uma lista de comandos que deve ser executada. Qualquer modificação nas branches sendo monitoradas dispara a execução do Travis e o mesmo fornece um relatório informando o status da build gerada. A atual versão do arquivo .travis.yml deste projeto se encontra assim:

language: ruby

rvm:
  - 2.2.0
env:
  - DB=sqlite

script:
  - bundle exec rake test

before_script:
  - bundle exec rake db:migrate --trace RAILS_ENV=test
  - bundle exec rake db:test:prepare

notifications:
  email:
    recipients:
      - pedrodelyra@gmail.com
branches:
  only:
    - master

Automatização da criação de ambientes de desenvolvimento com Vagrant

editar

O Vagrant é uma ferramenta utilizada para automatizar a criação de ambientes virtuais. Seu propósito é facilitar a configuração, reprodução e distribuição de ambientes virtuais e pode ser utilizado, por exemplo, para unificar o ambiente de desenvolvimento de uma equipe. Como os ambientes criados pelo Vagrant são virtuais (o Vagrant se baseia no uso de máquinas virtuais, por exemplo: VirtualBox, VMWare, etc...), estes podem ser construídos sobre qualquer sistema operacional que ofereça suporte ao Vagrant.

O uso do Vagrant é fácil e ágil, relataremos em seguida um pequeno tutorial de como usá-lo em sistemas Gnu/Linux.

Em primeiro lugar, é necessário realizar sua instalação. Utilize o gerenciador de pacotes da sua distribuição. No Debian, o pacote a ser instalado é:

$ sudo apt-get install vagrant

Em segundo lugar, siga ao diretório do projeto e execute o comando:

$ vagrant init

Este comando inicializa o Vagrant para o projetoatual e cria um arquivo de configuração utilizado pelo Vagrant denominado Vagrantfile. Este arquivo irá conter uma série de comentários que exemplificam o seu uso. Neste arquivo, é possível especificar, por exemplo, a box* que será utilizada na criação do ambiente e alguns scripts que devem ser executados durante a criação e configuração do novo ambiente. Em uma primeira versão do nosso projeto, o Vagrantfile se encontrava assim: * Uma box do Vagrant é uma imagem base de uma máquina virtual.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "hashicorp/precise64"
  config.vm.provision :shell, path: "bootstrap.sh"
end

Decidimos utilizar uma box já disponibilizada pela hashicorp que contém o sistema operacional Ubuntu 12.04 LTS 64-bit. O arquivo bootstrap.sh contém uma série de comandos que serão executados durante a construção do ambiente e que são responsáveis por configurar um ambiente de desenvolvimento pronto para o projeto Enem Amigo.

#!/usr/bin/env bash

apt-get update
sudo apt-get install -y vim
sudo apt-get install -y git
sudo apt-get install -y nodejs

gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3
sudo apt-get install -y curl
\curl -L https://get.rvm.io | bash -s stable --ruby --autolibs=enable --auto-dotfiles
source /usr/local/rvm/scripts/rvm && source /home/vagrant/.rvm/scripts/rvm
rvm install 2.2.0
rvm use --default 2.2.0
rvm gemset create rails4
rvm gemset use --default rails4

git clone https://github.com/pedrodelyra/enem-amigo.git
sudo chmod -R 777 enem-amigo/
cd enem-amigo
sudo gem install bundler
bundle install

Este arquivo será executado durante a criação do ambiente. Esta criação é realizada quando o seguinte comando é executado:

$ vagrant up

Após a execução deste comando, o ambiente de desenvolvimento já está criado e pronto para uso. Para acessá-lo, basta executar o comando:

$ vagrant ssh

Desta forma, é possível unificar o ambiente de desenvolvimento do projeto e diminuir as chances de uma certa funcionalidade funcionar apenas em um computador ou sistema específico. Qualquer desenvolvedor do projeto pode utilizar o ambiente criado pelo Vagrant de forma fácil e rápida. É possível levantar um ambiente pronto do zero em poucos minutos e essa automatização tende a produzir um aumento no rendimento da equipe.

Na versão final do projeto, foi utilizada a ferramenta Chef para substituir o shell script utilizado na versão anterior e automatizar a configuração do ambiente da box. O Vagrantfile foi alterado de forma que fossem adicionados recipes através do chef e que fosse especificado o caminho para os cookbooks. Um cookbook é uma unidade de configuração que possui recipes (coleções de recursos, definidas de acordo com padrões como nomes de recursos, atributos e ações), atributos, distribuições de arquivos e extensões do Chef.

# -*- mode: ruby -*-
# vi: set ft=ruby :

# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  # All Vagrant configuration is done here

  # Every Vagrant virtual environment requires a box to build off of.
  config.vm.box = "ubuntu/trusty64"

  config.ssh.forward_agent = true

  config.vm.network "private_network", ip: "10.3.3.3"

  # Forward ports for MongoDB and Express app
  config.vm.network "forwarded_port", guest: 27017, host: 27017, auto_correct: true
  config.vm.network "forwarded_port", guest: 3000, host: 3000, auto_correct: true

  config.vm.provision :shell, :inline => "sudo apt-get update -y"
  config.vm.provision :shell, :inline => "sudo apt-get install curl -y"
  config.vm.provision :shell, :inline => "curl -L https://www.opscode.com/chef/install.sh | sudo bash"
  config.vm.provision :shell, :inline => "git clone https://github.com/pedrodelyra/enem-amigo.git"

  config.vm.provision :chef_solo do |chef|
    # Paths to your cookbooks (on the host)
    chef.cookbooks_path = ["cookbooks"]
    # Add chef recipes
    chef.add_recipe 'nodejs'
    chef.add_recipe 'git' # Is required for NPM
    chef.add_recipe "apt"
    chef.add_recipe "ruby_build"
    chef.add_recipe "rbenv::user"
    chef.add_recipe "rbenv::vagrant"
    chef.add_recipe "vim"
  end

  # Install express and express-generator packages globally
  config.vm.provision :shell, :inline => "npm install -g express express-generator"

  # Share an additional folder to the guest VM. The first argument is
  # the path on the host to the actual folder. The second argument is
  # the path on the guest to mount the folder. And the optional third
  # argument is a set of non-required options.
  config.vm.synced_folder "../enem-amigo", "/enem-amigo"

end

No arquivo Cheffile foram especificados os cookbooks necessários para a configuração.

site 'https://supermarket.getchef.com/api/v1'

cookbook "nodejs"
cookbook "mongodb"
cookbook "git"

cookbook 'apt'
cookbook 'build-essential'
cookbook 'mysql', '5.5.3'
cookbook 'ruby_build', '2.2.0'
cookbook 'vim'

cookbook 'rvm',
  :git => 'https://github.com/fnichol/chef-rvm'

Empacotamento Debian

editar

Um pacote de software é uma coleção de arquivos agrupados em uma configuração pré-determinada para permitir a instalação e distribuição de um software. O objetivo do empacotamento de software é automatizar o processo de instalação, atualização, configuração e remoção de aplicações.

Um pacote debian é um pacote de software que pode ser instalado pelo sistema de gerenciamento de pacotes do Debian. Pacotes debian possuem a extensão ".deb". Neste projeto de gerência de configuração, foi realizado o empacotamento debian do Enem Amigo.

Antes de relatar como empacotamos o projeto, é interessante comentar sobre alguns conceitos centrais sobre empacotamento.

  • Tarball: um tarball é um conjunto de arquivos agrupados através do utilitário tar. Sua extensão é ".tar". Muitos arquivos .tar são comprimidos com o compressor de arquivos gzip e o resultado é o arquivo com extensão ".tar.gz" (esse é seu tarball).
  • Upstream tarball: é um tarball que contêm o código-fonte do software que será empacotado.
  • Source package: é um pacote construído a partir do upstream tarball e que é utilizado para a criação do pacote binário.
  • Binary package: é um pacote construído à partir do source package e que será instalado de fato (este é o .deb).

Durante o empacotamento, duas ferramentas essenciais do Debian foram utilizadas: o dh_make e o debuild. É necessário instalar alguns pacotes que são utilizados durante o empacotamento:

$ sudo apt-get install dh-make
$ sudo apt-get install build-essential

O empacotamento é um processo relativamente burocrático e exige que uma série de convenções sejam seguidas. Porém, este processo se faz necessário para garantir que a instalação daquela versão do software seja realizada corretamente. Em primeiro lugar, é necessário criar o upstream tarball do projeto. Para isso, basta adicionar ao nome do projeto a versão correspondente do software que será empacotado, no caso do Enem Amigo a seguinte renomeação foi feita:

$ mv enem-amigo enem-amigo-1.0

Em seguida, o tarball foi criado com os seguintes comandos:

$ tar zcf enem-amigo-1.0.tar.gz enem-amigo-1.0/
$ mv enem-amigo-1.0.tar.gz enem-amigo_1.0.orig.tar.gz

Vale lembrar que estes padrões de nome não são por acaso, as ferramentas de empacotamento do Debian esperam que os pacotes sigam estas convenções. O nome consiste no nome do source package, um underscore e a versão do software seguida pela extensão .orig.tar.gz. Em seguida, é necessário entrar na raíz do projeto e criar um diretório debian/ que será usado durante o empacotamento. Para realizar esta etapa, a ferramenta dh_make foi utilizada da seguinte forma:

$ cd enem-amigo-1.0/
$ dh_make -s

Após a confirmação de alguns dados, o dh_make irá criar o diretório debian com uma série de arquivos de exemplo. Optamos por remover estes arquivos:

$ rm debian/*.ex debian/*.EX

Vale a pena citar os principais arquivos deste diretório:

  • debian/control: contém alguns detalhes sobre o software empacotado e seu mantenedor.
  • debian/compat: contém o nível de compatibilidade do pacote. Deve ser 9.
  • debian/rules: é um arquivo Makefile que é executado durante a geração do pacote binário.
  • debian/source/format: contém a versão do formato do source package, que é "3.0 (quilt)".

Cada projeto possui seu próprio contexto, sua própria forma de geração de build, seus arquivos de configuração, manuais, enfim, suas peculiaridades. Portanto, é difícil fornecer uma receita genérica para empacotar um software, pois cada sistema possuirá um contexto próprio. No caso do Enem Amigo, nós criamos alguns arquivos para a execução da build do projeto e instalação do seu pacote em uma distribuição Debian.

Script utilizado para executar o projeto após sua instalação (enem-amigo)

#!/bin/bash

current_path=$(pwd)

cd /etc

if [ -e enem-amigo_1.0.orig.tar.gz ]; then
	sudo tar xzf enem-amigo_1.0.orig.tar.gz
	sudo rm enem-amigo_1.0.orig.tar.gz
fi

cd enem-amigo_1.0

bundle install > /dev/null
bundle exec rake db:migrate > /dev/null
bundle exec rails server

cd $current_path

Makefile utilizado para especificar como a instalação do software deve ser realizada

bindir = /usr/bin
srcdir = /etc

install:
	mkdir debian/enem-amigo
	mkdir debian/enem-amigo/usr
	mkdir debian/enem-amigo/usr/bin
	mkdir debian/enem-amigo/etc
	install enem-amigo $(DESTDIR)$(bindir)
	install ../enem-amigo_1.0.orig.tar.gz $(DESTDIR)$(srcdir)

Para a geração do pacote binário (.deb), basta executar o comando:

$ debuild -us -uc

Este comando irá gerar o pacote binário enem-amigo_1.0-1_amd64.deb que pode ser distribuído e instalado em sistemas Debian-like através do gerenciador de pacotes dpkg. Exemplo de instalação:

$ sudo dpkg -i enem-amigo_1.0-1_amd64.deb

O empacotamento Debian é uma técnica excelente para a distribuição de um software, porém, ela possui uma certa curva de aprendizado.

Deploy

editar

A realização do deploy foi através dos servidores em nuvem do DigitalOcean. O primeiro passo é a criação de um droplet, para isso é necessário criar um usuário e acessar o DigitalOcean onde pode ser criado e escolhido a distruição, os one-click apps, os snapshots (cria cópias do backup), o backup, o tamanho do seu droplet, a região que está o servidor e opções adicionais como private networking, ipv6, entre outros.

Através do SSH é possível o acesso ao servidor para o início da sua configuração, o IP para essa etapa é o Floating IP disponibilizado pelo DigitalOcean. Para a configuração, foram instalados os seguintes pacotes:

  • Nginx: um servidor proxy HTTP.
  • Sqlite3: o banco de dados utilizado na aplicação.
  • RVM: gerenciador de versões do ruby.
  • Puma: um servidor HTTP para aplicações Ruby/Rack.
  • Rails: framework utilizado na aplicação.
  • Bundler: Lê o Gemfile e instala automaticamente todas as gems.

O próximo passo necessário é criar uma chave SSH para o seu repositório no GitHub e associá-la ao seu droplet. O último passo é alterar as configurações no arquivo de configuração do nginx que fica em /config/nginx.conf.

upstream puma {
  server unix:///home/demo/apps/enem-amigo/shared/tmp/sockets/enem-amigo-puma.sock;
}

server {
  listen 80 default_server deferred;
  # server_name example.com;

  root /home/demo/apps/enem-amigo/current/public;
  access_log /home/demo/apps/enem-amigo/current/log/nginx.access.log;
  error_log /home/demo/apps/enem-amigo/current/log/nginx.error.log info;

  location ^~ /assets/ {
    gzip_static on;
    expires max;
    add_header Cache-Control public;
  }

  try_files $uri/index.html $uri @puma;
  location @puma {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    proxy_pass http://puma;
  }

  error_page 500 502 503 504 /500.html;
  client_max_body_size 10M;
  keepalive_timeout 10;
}