Enem Amigo
1 - Introdução
editarPropósito
editarEste 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
editarO 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
editarO repositório do projeto está disponível em https://github.com/pedrodelyra/enem-amigo.
2 - Gerência de Configuração de Software
editarOrganização, Responsabilidades e Interfaces
editarPapel | 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
editarGit
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
editarIdentificação da Configuração
editarA 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
editarOs 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
editarO 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
editarData | 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
editarAutomatização da Integração Contínua com Travis CI
editarA 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
editarO 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.
Chef
editarNa 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
editarUm 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
editarA 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;
}