Busine.me

Fonte: Wikiversidade

1. Introdução[editar | editar código-fonte]

1.1 Visão Geral[editar | editar código-fonte]

Esse documento irá descrever e especificar o plano de gerência de configuração que será aplicado no projeto Busine.me Web. O projeto se trata de um aplicativo que pretende resolver problemas de mobilidade urbana, e está sendo desenvolvido nas disciplinas de GPP e MDS da Universidade de Brasilia. A wiki do projeto pode ser acessada a partir do seguinte link:

http://lappis.unb.br/redm/projects/grupo-2-busine-me/wiki

Na wiki é possível ver documentação de Visão do projeto, arquitetura, casos de uso etc. A documentação do projeto também está em desenvolvimento.


O repositório de desenvolvimento da disciplina MDS pode ser encontrado no seguinte link:

https://github.com/aldarionsevero/BusinemeWeb

O repositório oficial do aplicativo pode ser encontrado nesse outro link:

https://github.com/Busineme/BusinemeWeb

Por ser um aplicativo que começou seu desnvolvimeno nesse semestre (2015/1), o mesmo da confecção desse documento, várias abordagens e melhorias de GCS podem ser feitas para, tanto facilitar o desenvolvimento, quanto facilitar manutenção e implantação.

1.2 Propósito[editar | editar código-fonte]

Com o plano proposto por esse documento, espera-se que melhorias significativas com relação a Gerência de configuração de Software sejam assimiladas pelo software Busine.me Web. A metodologia proposta por esse plano será desenvolvida e implantada durante 2 meses da disciplina de GCS, juntamente com o desenvolvimento do software das diciplinas de MDS e GPP, mas após esses dois meses essas melhorias continuarão trazendo as melhorias propostas enquanto elas estiverem sendo utilizadas. A disciplina de MDS requere que seus projetos tenham versionamento e controle de mudança, que tenha testes e razoável cobertura, logo essa parte fica fora do escopo deste documento. Assim sendo, integração contínua e Automação de implantação passa a ser o escopo real da metodologia proposta nesse documento.


1.3 Escopo[editar | editar código-fonte]

O escopo do projeto abrange as seguintes demandas para o software:

  • Automação de testes e de builds por meio de integração contínua utilizando Travis
  • Automação de implantação utilizando a ferramenta Chef
  • Para auxiliar o Travis utilizaremos a ferramenta Fabric ou Chake para executar comandos em máquinas remotas auxiliando a implantação automática.
  • Garantir localmente o mesmo ambiente versionado com a ferramenta Vagrant, evitando problemas de quebras ao utilizar localhost.

1.4 Definições, Acrônimos e Abreviações[editar | editar código-fonte]

Abreviação Significado
GCS Gerência de Configuração de Software
MDS Método de Desenvolvimento de Software
GPP Gerência de Projeto e Portifólio de Software
IC Integração Contínua
VM Virtual Machine (máquina virtual)
AWS Amazon Web Service


2. Milestones[editar | editar código-fonte]

Os milestones serão os marcos dos pequenos entregáveis e releases reais do projeto.

DATA Descrição
9/05/2015 Configurar repositório para que o script do Travis execute a suite de testes, chame o serviço do coveralls e poste no Slack
02/06/2015 Atomatização da implantação utilizando o Chef
16/06/2015 Utilização do Fabric ou Chake para facilitar utilização do Chef
27/06/2015 Finalizar o fluxo de automação e integração


3. Andamento[editar | editar código-fonte]

Andamento do desenvolvimento e alterações de escopo do projeto.

3.1 Alterações de Escopo[editar | editar código-fonte]

Inicialmente, a integração contínua a ser empregada no projeto estava planejada para acontecer com a ajuda da ferramenta Travis, mas já que a integração contínua irá disparar a implantação automática usando o rake + chef (+ chake) para execução de comandos na máquina remota, diversas informações, como senhas ssh, iriam ficar visíveis no serviço aberto do travis. Para tornar isso fechado, decidimos mudar a ferramenta de integração contínua do Travis para o Jenkins, e levantá-lo em um servidor pessoal.

Antes Agora
Travis Jenkins
Fabric ou Chake Decisão pelo Chake
Serviço aberto inseguro Instancia própria com mais segurança

3.2 Progresso[editar | editar código-fonte]

Progresso de tarefas do desenvolvimento de GSC no projeto.

3.2.1 Feito[editar | editar código-fonte]
  • Sincronização do repositório com o serviço do Travis
  • Estudo a respeito do Chef e das dependências que ele precisa trazer
    • Dependências para trazer na receita de configuração de ambiente de desenvolvimento
    • Dependências para trazer na receita de configuração de ambiente de implantação
  • Estudo a respeito do Fabric e Chake, e decisão pelo Fabric
    • Decisão pela mudança de ferramenta de IC
  • Utilização de uma VM na Amazon Web Service (trial de um ano grátis) para a instância do Jenkins
    • Configuração do servidor nginx para o levantamento do Jenkins
    • Configuração do Jenkins, seus plugins, geração de relatórios, e Jobs para IC do projeto
  • Desenvolvimento da receita de configuração de ambiente de desenvolvimento (agora sendo a mesma que a de deploy, mas generalizada para funcionar local ou deploy)
  • Adaptação do script do Jenkins para integração entre IC e ambiente de implantação com o Chake

4. Passo a passo da execução do projeto[editar | editar código-fonte]

Os temas abordados nesse projeto, como integração contínua, automatização de ambientes e de deploy, podem ser reproduzidos em diversos outros projetos, e de maneira geral, seguem passo a passo semelhante. Por esse motivo, a execução desse projeto será detalhada aqui.

4.1 VMs em Web Service[editar | editar código-fonte]

Existem diversas opções de Web Services disponíveis, algumas pagas, e outras com período de trial. Utilizamos duas VMs de ubuntu 15 da azure (pagas) para implantar a aplicação. Também utilizamos uma VM ubuntu 14.04 (trial) para configuração do jenkins.

4.1.1 Azure[editar | editar código-fonte]

O Microsoft Azure é um serviço pago, entretanto, um dos integrantes do Busine.me possui o plano BizSpark, onde o usuário tem direito à US$150,00 mensais para gastar com os serviços do Azure. Para criar uma VM no Azure:

  • Acesse o dashboard do Azure[1] e faça login na sua conta.
  • Clique em "+ new" -> "Compute" -> "Virtual Machines" -> "From Gallery"
  • Escolha uma das imagens disponíveis. Para o projeto, foi escolhido o Ubuntu Server 15.04.
  • Defina o nome da sua VM, que será usado como DNS, sua configuração e o usuário padrão, bem como a forma de login, se por chave .pem ou senha. Para o projeto, foram definidas duas VMs:
    • businemeweb.cloudapp.net: 1 core, 1.75 GB RAM. Login por senha.
    • businemeapi.cloudapp.net: 1 core, 1.75 GB RAM. Login por senha.
  • Defina as portas/saídas da VM. Para o projeto, em todas as VMs foram abertas as portas:
    • 22 - SSH
    • 80 - HTTP
  • Finalize a criação da VM e aguarde até que o Azure termine de levantar a máquina.
4.1.2 Amazon Web Service[editar | editar código-fonte]

Para criar uma VM na AWS, é necessário primeiro ter uma conta na amazon (mesma conta do site de compras).

  • Com a conta criada, acesse https://aws.amazon.com/, faça login, e clique em MyAccount e em AWS management console.
  • Depois siga para VMs EC2.
  • Clique em launch Instance e então na distro desejada (Ubuntu 14.04).
  • Siga as configurações, revendo os valores padrões. Nesse projeto só algumas portas sofreram port forward, mas não é necessário fazer isso nessemomento.
  • Siga até o lanch, crie um novo keypair, nomei-o e faça o download do mesmo e guarde com cuidade o arquivo. Ele é utilizado para fazer ssh na máquina.
  • Finalize o processo e então terá uma VM levantada pronta para acesso remoto.
  • Para acessá-la via ssh, fique no diretório onde baixou o arquivo ".pem" e rode o comando utilizando nome do arquivo e ip da máquina:
$ ssh -i nome_do_arquivo.pem ubuntu@XX.XX.XXX.XXX

4.2 Levantar os Serviços[editar | editar código-fonte]

Nesse projeto diversas aplicações devem ser levantadas por trás de um nginx reverse proxy. Para o jenkins na maquina da AWS é necessário seguir as instruções desse link https://wiki.jenkins-ci.org/display/JENKINS/Running+Jenkins+behind+Nginx.

Para a aplicação em si rodando no servidor de homologação, ou no vagrant local, veja no tópico falando sobre a receita que configura isso.

4.3 Como Aplicar IC[editar | editar código-fonte]

Após devidas configurações do supervisor e nginx do tópico anterior, é necessário iniciar o jenkins por trás dessa configuração e então configurá-lo. Para instalar o Jenkins:

$ wget -q -O - https://jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
$ sudo apt-get update
$ sudo apt-get install jenkins
4.3.1 Plugins[editar | editar código-fonte]

Para instalar plugins no Jenkins basta navegar por "Manage Jenkins", "Manage Plugins" e selecionar a aba "Available". Os plugins necessários são:

  • Cobertura
  • Git client plugin
  • Git parameter plugin
  • Git plugin
  • Git server plugin
  • GitHub API plugin
  • GitHub plugin

E assim que forem instalados, selecione opção de reiniciar o Jenkins para que estejam utilizáveis.

4.3.2 Configuração Jenkins[editar | editar código-fonte]
  • Estando na dashboard do Jenkins, Selecione "New Item".
  • Nomeie o Job que irá rodar builds da aplicação.
  • Coloque o link do projto no GitHub (https://github.com/aldarionsevero/BusinemeWeb/)
  • Em Source Code Management, selecione git. Coloque a branch a ser monitorada, e suas credenciais.
  • Escolha qual evnto irá dispará uma build do projeto (push).
  • E por fim coloque os passos necessários anteriores para execução dos testes.

Nesse projeo são (pode-se separar em diversos blocos de "Execute Shell"):

sudo apt-get install ruby chef python2.7 python-pip -y && \
sudo apt-get install libxml2 && \
sudo apt-get install libxslt1.1 && \
sudo apt-get install libxml2-dev && \
sudo apt-get install libxslt1-dev && \
sudo apt-get install python-libxml2 && \
sudo apt-get install python-libxslt1 && \
sudo apt-get install python-dev && \
sudo apt-get install python-lxml && \
sudo apt-get install python-setuptools && \
sudo pip install -r requirements.txt && \
sudo pip install python-Levenshtein && \
cp configuration/databases.py.template configuration/databases.py && \
cp configuration/security.py.template configuration/security.py && \
cp configuration/api.py.template configuration/api.py && \
rm models/migrations/0* && \
python manage.py makemigrations && \
python manage.py migrate && \
python manage.py jenkins && \
clonedigger --cpd-output -o ./reports/clonedigger.xml . && \
coverage run manage.py test && \

4.5 Vagrant[editar | editar código-fonte]

O Vagrant é a ferraemnta utilizada no projeto para gerenciamento de VMs para o ambiente de desenvolvimento. A criação e destruição de um abiente limpo e padronizado com o Vagrant garante integridade do ambiente, e é possível seguindo os seguintes passos:

$ vagrant init

Esse comando cria o vagrant file que utilizaremos para configuração das VMS

  • Não utilizaremos o chef como provisioner do Vagrant, como inicialmente planejado (tutorial para seguir com provisioner pode ser encontrado em outros projetos dessa turma), em vez disso utilizaremos o rake para acionar funcionalidades do chef por intermédio do chake. Dessa forma o nosso vagrant file fica assim:
# -*- mode: ruby -*-
# vi: set ft=ruby :
require 'yaml'

Vagrant.configure(2) do |config|
  config.vm.box = "ubuntu/trusty64"

  env = ENV.fetch('BUSINEME_ENV', 'local')

  if File.exist?("config/#{env}/ips.yaml")
    ips = YAML.load_file("config/#{env}/ips.yaml")
  else
    ips = nil
  end

  config.vm.define 'api' do |api|
    api.vm.network 'private_network', ip: ips['api'] if ips
    api.vm.network "forwarded_port", guest: 8080, host: 8079
  end

  config.vm.define 'web' do |web|
    web.vm.network 'private_network', ip: ips['web'] if ips
    web.vm.network "forwarded_port", guest: 8000, host: 8001
  end
end

Podemos observar que temos uma box limpa do ubuntu 14.04 (trusty64), que setamos um ambiente local e outro de deploy (BUSINEME_ENV), que fazemos as configurações de ip por meio de um arquivo yaml e que levantamos as VMS com essas configurações. Esses arquivos de configuração dependem do chake e serão melhor explicados no tópico apropriado.

4.5 Integrar rake e chef com o chake[editar | editar código-fonte]

A parte mais trabalhosa do projeto vem dessa integração. Para isso é necessário primeiro instalar ruby, rake, chef e o chake:

$ sudo apt-get install ruby
$ sudo gem install rake chef chake

Em seguida partimos para a configuração de tudo nos diretórios onde temos o Vagrantfile.

4.5.1 Local (Vagrant)[editar | editar código-fonte]

Nesse diretório, executamos o seguinte comando:

$ chake init

que criará os seguintes arquivos:

[create] nodes.yaml                                    # que configurará os nós em que as receitas serão executadas
[create] config.rb                                     # que irá linkar os diretórios do chef para que o rake consiga puxar as funcionalidades
[ mkdir] config/roles                                  # iremos mudar para que configuremos nossos dois ambientes (local, BUSINEME_ENV)
[ mkdir] cookbooks/basics/recipes/                     # receita básica (geralmente executada em todos os nós)
[create] cookbooks/basics/recipes/default.rb
[create] Rakefile                                      # Arquivo de configuração do rake para nós etc
  • Antes de tudo iremos configurar o arquivo Rakefile, para que ao longo do tutorial possamos, além de levantar a VM, possamos rodar o rake.

Esse arquivo irá se utilizar de outros arquivos de configuração que iremos confecionar para que o rake possa passar valores que estarão nos arquivos dentro da pasta config, para as receitas e templates. Além disso seta nós e o script para gerar o bootstrap_common do ssh_config.

require 'yaml'


$BUSINEME_ENV = ENV.fetch('BUSINEME_ENV','local')


ips_file = "config/#{$BUSINEME_ENV}/ips.yaml"
ssh_config_file = "config/#{$BUSINEME_ENV}/ssh_config"
config_file = "config/#{$BUSINEME_ENV}/config.yaml"

ENV['CHAKE_TMPDIR'] = "tmp/chake.#{$BUSINEME_ENV}"
ENV['CHAKE_SSH_CONFIG'] = ssh_config_file

require "chake"

ips ||= YAML.load_file(ips_file)
config ||= YAML.load_file(config_file)

$nodes.each do |node|
	node.data['config'] = config
	node.data['peers'] = ips
end

file 'ssh_config.erb'
if ['local'].include?($BUSINEME_ENV)
	file ssh_config_file => ['nodes.yaml', ips_file, 'ssh_config.erb', 'Rakefile'] do |t|
		require 'erb'
		template = ERB.new(File.read('ssh_config.erb'))
		File.open(t.name, 'w') do |f|
			f.write(template.result(binding))
		end
	puts 'ERB %s' % t.name
	end
end

task :bootstrap_common => 'config/local/ssh_config'

  • Em seguida, após criar a estrutura de diretórios é deletar o diretório roles e criar dois diretórios novos: "local", "homologa", que são nossos ambientes de desenvolvimento e de deploy.
  • Em cada um desses diretórios iremos criar os seguintes arquivos:
$ cd config/local
$ touch config.yaml
$ touch ips.yaml
$ ssh_config                                           # Esse arquivo pode ser gerado pelo bootstrap_common do rake, mas também pode ser feito na mão (enquanto o bootstrap_não está genérico)

O mesmo pro outro diretório:

$ cd config/homologa
$ touch config.yaml
$ touch ips.yaml
$ ssh_config  

No arquivo config.yaml iremos colocar todos os paths de diretórios, URLs necessárias, nomes e versões. Principalmente as que sabemos que serão diferentes entre aplicação e api.

O arquivo ips.yaml segue mesmo padrão, mas colocaremos somente ips.

O arquivo ssh_config irá guardar as configurações de ssh e localização de chaves para as VMs.

Iremos configurar a parte local primeiro então os conteúdos desses arquivos ficam:

# config.yaml (não copie esse comentario)
DIRECTORIES:
  API_REPO: /vagrant/repo/busineme-api
  WEB_REPO: /vagrant/repo/busineme-web
APPLICATION:
  WEB_REPOSITORY: https://github.com/Busineme/BusinemeWeb.git
  API_REPOSITORY: https://github.com/Busineme/BusinemeAPI.git
  API_URL: http://10.10.10.2:8080/api/v1/
  SECRET_KEY: secret-key
DATABASE:
  NAME: busineme
  USER: busineme
  PASSWORD: 1234
  VERSION: 9.3
# ips.yaml (não copie esse comentário)
api:	10.10.10.2
web:	10.10.10.3
# ssh_config (não copie esse comentário)
Host *
  User vagrant
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentitiesOnly yes
  LogLevel FATAL


Host api
  Hostname 10.10.10.2
  Port 22
  IdentityFile .vagrant/machines/api/virtualbox/private_key

Host web
  Hostname 10.10.10.3
  Port 22
  IdentityFile .vagrant/machines/web/virtualbox/private_key


# vim: ft=sshconfig
  • Em seguida iremos configurar nossos nós (nessa aplicação: API e WEB). Fazemos isso no arquivo nodes.yaml. Aqui ja podemos chamar as receitas que posteriormente incluiremos nos diretórios de cookbooks (comente se quiser já levantar o vagrant com o comando vagrant up e uma VM limpa).
# dois nós chamando suas receitas
api:
  run_list:
    - recipe[basics]
  #  - recipe[busineme::postgresql] # comentado pois ainda iremos fazer essa receita
  #  - recipe[busineme::api]

web:
  run_list:
    - recipe[basics]
  #  - recipe[busineme::postgresql]
  #  - recipe[busineme::web]
  • O conteudo do config.rb pode ser mantido.
  • Agora baixaremos as recipes/cookbooks externas que usaremos, e então faremos a nossa recipe interna do chef.
    • Baixe as seguintes cookbooks no diretório cookbooks: git, apt, build-essential, chef-sugar, chef_handler, dmg, openssl, windows, yum, yum-epel. O site para o download é: https://supermarket.chef.io/
    • No arquivo cookbooks/basics/recipes/default.rb, adicione o conteúdo:
# default.rb
execute "apt-get update"
package 'openssh-server'

Para dar um apt-get update e ter servidor ssh em suas VMs, antes de rodar outras receitas.

  • Crie os seguintes diretórios agora:
$ mkdir busineme/files/default busineme/recipes/ busineme/templates/default

No files/default irão os arquivos que, durante a configuração, deverão ser copiados sem alteração. No recipes criaremos nossas receitas. No templates default, colocaremos os arquivos que precisam de alguma generalização antes de serem copiados para algum diretório, durante a configuração feita pela receita.

Já que são muitos arquivos de configuração e templates, recomendamos consulta ao repositório:

https://github.com/Busineme/BusinemeChef/tree/master/cookbooks/busineme/files/default

https://github.com/Busineme/BusinemeChef/tree/master/cookbooks/busineme/templates/default

  • Agora criaremos nossas receitas internas:
$ touch busineme/recipes/web.rb busineme/recipes/api.rb busineme/recipes/postgresql.rb

A receita da base de dados postgresql serve para a criação do usuário, criação do banco e inicialização do serviço. E tem o seguinte conteúdo:

#instala psql
package "postgresql"

# modo debug para ambiente local
if ['local'].include?($BUSINEME_ENV)
  DEBUG = 'True'
  directory "#{REPODIR}" do
    recursive true
  end
else
  DEBUG = 'False'
end

# arquivo configuracao
template "/etc/postgresql/#{node['config']['DATABASE']['VERSION']}/main/pg_hba.conf" do
	source 'pg_hba.conf.erb'
	user 'postgres'
	group 'postgres'
	mode 0600
	notifies :restart, 'service[postgresql]', :immediately
end

# criacao do usuario
DB_USER = node['config']['DATABASE']['USER']
DB_PASSWORD = node['config']['DATABASE']['PASSWORD']
DB_NAME = node['config']['DATABASE']['NAME']
execute "createuser:#{DB_USER}" do
	command "psql -c \"CREATE USER #{DB_USER} WITH PASSWORD '#{DB_PASSWORD}';\""
	user 'postgres'
	not_if "sudo -u postgres psql -c \"select * from pg_user where usename = '#{DB_USER}';\" | grep -c #{DB_USER}"
end

# criacao do banco
execute "createdb:#{DB_NAME}" do
	command "createdb #{DB_NAME} --owner=#{DB_USER}"
	user 'postgres'
	not_if "sudo -u postgres psql -c \"select * from pg_database where datname = '#{DB_NAME}';\" | grep -c #{DB_NAME}"
end

service 'postgresql' do
	action [:enable, :start]
	supports :restart => true
end
  • A receita web.rb é a que configurará a máquina que rodará a aplicação principal. Por partes temos:

Configuração de ambiente local e de deploy e instalações de dependências.

# Variables
$BUSINEME_ENV = ENV.fetch('BUSINEME_ENV', 'local')
package "vim"

package "python2.7" 
package "python-pip" 
package "python-dev"
package "postgresql-contrib"
package "libpq-dev" 
package "postgresql"
package "git"

package "libxml2"
package "libxslt1.1"
package "libxml2-dev"
package "libxslt1-dev"
package "python-libxml2"
package "python-libxslt1"
package "python-lxml"
package "python-setuptools"
package "python-Levenshtein"
package "python-psycopg2"
execute "pip install gunicorn"
package "nginx"
package "supervisor"
package "nginx"


include_recipe "git"

Modo debug para ambiente local e sem debug para ambiente de deploy.

REPODIR = node['config']['DIRECTORIES']['WEB_REPO']
if ['local'].include?($BUSINEME_ENV)
  DEBUG = 'True'
  directory "#{REPODIR}" do
    recursive true
  end
else
  DEBUG = 'False'
end

Clone do repositorio usando a receita externa do git.

git "#{REPODIR}" do
  repository node['config']['APPLICATION']['WEB_REPOSITORY']
  action :sync
end

Instalaçã de requerimentos especificos da aplicação e configuração de ambiente da mesma por meio de templates.

execute 'pip install -r requirements.txt' do
  cwd "#{REPODIR}"
end

template "#{REPODIR}/configuration/databases.py" do
  source "databases.py.erb"
end

template "#{REPODIR}/configuration/security.py" do
  source "security.py.erb"
  variables({:DEBUG => DEBUG})
end

template "#{REPODIR}/configuration/api.py" do
  source "api.py.erb"
end

Criação das tabelas no banco que ja foi criado pela receita do postgresql.

execute 'python manage.py makemigrations' do
  cwd "#{REPODIR}"
end

execute 'python manage.py migrate' do
  cwd "#{REPODIR}"
end

Configuração do supervisor para levantar o nginx como processo, script para levantar o gunicorn que faz o nginx entender o projeto Django como aplicação.

template "/etc/supervisor/conf.d/busineme.conf" do
  source "busineme.conf.erb"
  variables({:REPODIR => REPODIR})
  mode 0600
end

template "#{REPODIR}/gunicorn_script" do
  source "gunicorn_script.erb"
  variables({:REPODIR => REPODIR})
  mode 0775
end

service 'supervisor' do
  action :restart
end

execute 'supervisorctl start busineme' do
  cwd "#{REPODIR}"
end

file "/etc/nginx/sites-available/default" do
  action :delete
end

file "/etc/nginx/sites-enabled/default" do
  action :delete
end

template "/etc/nginx/sites-available/busineme.conf" do
  source "busineme-nginx.conf.erb"
  variables({:REPODIR => REPODIR})
  mode 0600
end

link "/etc/nginx/sites-enabled/busineme.conf" do
  to "/etc/nginx/sites-available/busineme.conf"
  notifies :restart, "service[nginx]"
end

service "nginx" do
  action [:enable, :start]
  supports :restart => true
end

Resultado final:

# Variables
$BUSINEME_ENV = ENV.fetch('BUSINEME_ENV', 'local')
package "vim"

package "python2.7" 
package "python-pip" 
package "python-dev"
package "postgresql-contrib"
package "libpq-dev" 
package "postgresql"
package "git"

package "libxml2"
package "libxslt1.1"
package "libxml2-dev"
package "libxslt1-dev"
package "python-libxml2"
package "python-libxslt1"
package "python-lxml"
package "python-setuptools"
package "python-Levenshtein"
package "python-psycopg2"
execute "pip install gunicorn"
package "nginx"
package "supervisor"
package "nginx"


include_recipe "git"

REPODIR = node['config']['DIRECTORIES']['WEB_REPO']
if ['local'].include?($BUSINEME_ENV)
  DEBUG = 'True'
  directory "#{REPODIR}" do
    recursive true
  end
else
  DEBUG = 'False'
end

git "#{REPODIR}" do
  repository node['config']['APPLICATION']['WEB_REPOSITORY']
  action :sync
end


execute 'pip install -r requirements.txt' do
  cwd "#{REPODIR}"
end

template "#{REPODIR}/configuration/databases.py" do
  source "databases.py.erb"
end

template "#{REPODIR}/configuration/security.py" do
  source "security.py.erb"
  variables({:DEBUG => DEBUG})
end

template "#{REPODIR}/configuration/api.py" do
  source "api.py.erb"
end


execute 'python manage.py makemigrations' do
  cwd "#{REPODIR}"
end

execute 'python manage.py migrate' do
  cwd "#{REPODIR}"
end

template "/etc/supervisor/conf.d/busineme.conf" do
  source "busineme.conf.erb"
  variables({:REPODIR => REPODIR})
  mode 0600
end

template "#{REPODIR}/gunicorn_script" do
  source "gunicorn_script.erb"
  variables({:REPODIR => REPODIR})
  mode 0775
end

service 'supervisor' do
  action :restart
end

execute 'supervisorctl start busineme' do
  cwd "#{REPODIR}"
end

file "/etc/nginx/sites-available/default" do
  action :delete
end

file "/etc/nginx/sites-enabled/default" do
  action :delete
end

template "/etc/nginx/sites-available/busineme.conf" do
  source "busineme-nginx.conf.erb"
  variables({:REPODIR => REPODIR})
  mode 0600
end

link "/etc/nginx/sites-enabled/busineme.conf" do
  to "/etc/nginx/sites-available/busineme.conf"
  notifies :restart, "service[nginx]"
end

service "nginx" do
  action [:enable, :start]
  supports :restart => true
end
  • Com isso já é possível levantar o ambiente de desenvolvimento local. Basta seguir o diagrama de desenvolviemnto com os seguintes comandos:
$ vagrant up
$ rake # ou rake converge:web ou rake convege:api para rodar receitas específicas

Esses dois comandos podem demorar bastante pois levantam a VM sem nada e instalam tudo das receitas. A segunda vez irá só atualizar com mudanças (se houverem) nas receitas. Se for necessário destruir as VMs e todos seus vestígios, rode:

$ vagrant destroy

Para logar em alguma vm use:

$ rake login:web

ou

$ rake login:api 
  • Para visualizar o desenvolvimento, não é necessário rodar o runserver pra VM web, pois ele já está rodando pelo nginx. Basta acessar no ip 10.10.10.3 (arquivo de configuração de ips).
  • Entretanto é necessário rodar o runserver da API
$ ./manage.py runserver 0.0.0.0:8080


4.5.2 Deploy[editar | editar código-fonte]

Para as configurações de deploy temos que ter conteúdo diferentes nos arquivos config.yaml, ips.yaml e ssh_config, agora no diretorio config/homologa. Esses conteúdos diferentes estão sendo passados para os templates e para as receitas, justamente para fazer com que sejam genéricos para rodarem locais ou em deploy.

Esses conteúdos serão:

# config.yaml (não copie esse comentário)
DIRECTORIES:
  API_REPO: /opt/busineme-api
  WEB_REPO: /opt/busineme-web
APPLICATION:
  WEB_REPOSITORY: https://github.com/Busineme/BusinemeWeb.git
  API_REPOSITORY: https://github.com/Busineme/BusinemeAPI.git
  API_URL: http://businemeweb.cloudapp.net/api/v1/
  SECRET_KEY: secret-key
DATABASE:
  NAME: busineme
  USER: busineme
  PASSWORD: 1234
  VERSION: 9.4
# ips.yaml (não copie esse comentário)
api:	23.96.43.247
web:	23.96.100.196
# ssh_config
Host api
 Hostname 23.96.43.247
 Port 22
 User busineme

Host web
 Hostname 23.96.100.196
 Port 22
 User busineme

# vim: ft=sshconfig
  • Também é necessário adicionar um post build action no Jenkins fazendo o seguinte:
git pull https://github.com/Busineme/BusinemeChef.git && \
cd BusinemeChef && \
sudo gem install rake && \
sudo gem install chake && \
rake BUSINEME_ENV=homologa

Sendo que o repositório do BusinemeChef na máquina do jenkins já tem que estar clonado.

  • Para rodar o chake para deploy:
$ rake BUSINEME_ENV=homologa
  • Para fazer um teste rápido talvez seja interessante rodar um
$ rake run BUSINEME_ENV=homologa

E digitar

$ date

Para verificar se o output é semelhante a esse:

api: $ date
api: Thu Jul  2 04:41:18 UTC 2015
web: $ date
web: Thu Jul  2 04:41:19 UTC 2015

Para ter certeza que tudo está em ordem antes de executar receitas.


5. Resultado[editar | editar código-fonte]

Diagrama de automatização do ambiente de desenvolvimento.[editar | editar código-fonte]

Devel using chake in busineme project.

Diagrama de automatização de build e deploy.[editar | editar código-fonte]

Deploy using chake in busineme project.