Implementando Aplicações Rails Com Capistrano

Chegou a hora de implantar a aplicação para os primeiros testes do cliente?
Vamos ver como a dupla sertaneja Rails & Capistrano soam bem nesta tarefa.

O Capistrano é uma gem para implantar (deploy) aplicações web. Inicialmente desenvolvida para Rails, tem a finalidade de enviar seu código fonte para um servidor web e permitir o versionamento, ou seja, te dando super poderes para voltar a versão anterior do seu código caso algo dê errado na versão atual. Com um pouquinho de configuração o Capistrano pode ser utilizado para outros framework/linguagem.

Vamos adimitir que você já tenha conhecimento em Sistemas de Controle de Versão (Git, SVN, etc) e que seu ambiente de desenvolvimento esteja funfando com a aplicação.

Hoje foi o meu primeiro contato com o Capistrano, abaixo segue minhas descobertas.

Requisitos

Para executar esta tarefa temos que verificar em nossa maleta de ferramentas se está presente:

  • Ruby
  • Uma aplicação (no meu caso em Rails)
  • Servidor Web com suporte a SSH
  • Terminal (bash, sh, etc…)
  • Um repositório (No meu caso GIT)

Instalação

Como citado, o Capistrano é um gem e com isso você pode instalar do jeito tradicional mesmo.
É, aquele fácil! Fazemos assim:

bash
1
gem install capistrano

O capistrano adiciona alguns utilitários de linha de comando, o cap e capify iremos conhecer mais abaixo. Também é possível adicionar esta gem no arquivo GemFile do seu projeto.

ruby
1
gem 'capistrano'

e depois executar o bundle install em seu terminal.

Iniciando

Agora utilizamos o capify , nosso amigo de linha de comando para fazer com que o Capistrano monitore nossa work area e nos dê opções para configurá-lo. Primeiramente temos que estar na raiz do diretório do nosso projeto.

bash
1
cd /app_rails/

Agora é só executar!

bash
1
capify .

Com isso ganhamos dois arquivos em nosso projeto, são eles:

  • capifile –> Possui referências as bibliotecas usadas pelo Capistrano e é responsável em carregá-las.
  • config/deploy.rb –> Este possui todas diretrizes para configurar sua implantação, geralmente precisamos editar apenas este.

Confirgurações

O Capistrano precisa de algumas informações para que tudo funcione conforme esperamos e isso fazemos editando o arquivo config/deploy.rb. Estou usando um projeto fictício apenas para exemplo, fique atendo as informações que devem ser substituidas conforme as suas configurações.
Vamos lá então!

A) Informações do projeto

ruby
1
2
3
set :application, "app_rails"       # O nome do projeto
set :keep_releases, 5               # Isso guardar os 5 últimos deploys
set :rails_env,     "production"    # O ambiente em que o Rails irá atuar

Toda vez que adicionarmos uma nova funcionalidade ao projeto iremos implementá-la no servidor para que outros tenham acesso e nesse processo, o Capistrano faz o versionamento mantendo seu release anterior. Na linha 2 dizemos que será mantido as 5 últimas atualizações, assim caso algo saia errado neste novo release, podemos usar um comandinho salvador da pátria.

bash
1
cap rollback

com isso voltamos ao release que estava funfando.

B) SCM (source code manager)

ruby
1
2
3
4
set :scm, 'git'
set :repository,  "git@github.com:LeandroSNunes/app_rails.git"
set :branch, 'master'
set :deploy_via, :remote_cache

No meu caso uso Git como repositório e informo na linha 1. A linha 4 é informado ao Capistrano que ele não precisa pegar todo repositório toda vez que subirmos um novo release, ele somente irá buscar as modificações.

C) Informações do servidor

ruby
1
2
3
4
5
6
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
set :user, "leandro"
set :use_sudo, false
server "leandronunes.com.br", :web, :app, :db, :primary => true
set :deploy_to, "/www/app_rails.leandronunes.com.br/#{application}"

Na linha 2 permitimos que o SSH carregue nossa chave para o servidor para que de lá seja acessado o github.
O usuário informado precisa ter permissões de escrita no servidor.
Alguns comandos por default são executados com sudo, porém se tiver usando um servidor compartilhado e que não tiver acesso de superusuário, informe para não utilizar o sudo como na linha 4.
O Capistrano entende que sua aplicação irá fazer muito sucesso e que seja preciso distribuí-la em vários servidores, no meu caso estou enviando tudo para o mesmo lugar então a linha 5 é uma forma otimizada de informar isso.

Caso precise redirecionar serviços para outros servidores, você pode substituir a linha 5 por:

ruby
1
2
3
role :web, 'dominio'
role :app, 'dominio'
role :db,  'dominio', :primary => true

Ops! Executando.

Agora é a hora! Vamos implantar nossa aplicação no servidor, começamos verificando se tudo está OK.

bash
1
cap deploy:check

Tudo correndo bem, você será informado. Seguindo, criaremos a estrutura de pastas no servidor.

bash
1
cap deploy:setup

O que fizemos? Com isso será criado duas pastas (release e shared) e ainda um link simbólico chamado current apontando para o último release. Na pasta releases é criado uma pasta para o deploy efetuado. A pasta shared serve para armazenar arquivos que serão compartilhados entre os releases, como logs, imagens, arquivos de configuração, etc…

Quando trabalhamos com Rails, Git e mais de um desenvolvedor é de prática adicionar nosso arquivo database.yml ao .gitignore, fazendo com que este não seja monitorado e conseguentemente não enviado para o repositório, assim configuramos um único arquivo de banco de dados e colocamos na pasta shared para que todos releases compartilhem a mesma configuração. Mais abaixo vamos adicionar uma tarefa pra fazer isso.

A) Criando tarefas para o Capistrano

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
namespace :deploy do
#   task :start do ; end
#   task :stop do ; end
   task :restart, :roles => :app, :except => { :no_release => true } do
     run "touch #{current_path}/tmp/restart.txt"
   end
   task :database, :roles => :app do
     run "cp #{deploy_to}/#{shared_dir}/database.yml #{release_path}/config/"
   end
   task :permission, :roles => [:web, :db, :app] do
     run "chmod 755 #{release_path}/public -R"
   end
end

namespace :assets do
    task :symlink, :roles => :app do
      assets.create_dir
        run <<-CMD
         rm -rf  #{release_path}/public/images/upload &&
         ln -nfs #{shared_path}/upload #{release_path}/public/images/upload
       CMD
    end
      task :create_dir, :roles => :app do
        run "mkdir -p #{shared_path}/upload"
      end
end

after "deploy:assets:symlink", 'deploy:database'
after "deploy:update_code", 'deploy:permission'

Ao concluir o deploy é necessário reiniciar o servidor para que as novas configurações entrem em vigor, podemos fazer isso simplesmente atualizando o arquivos tmp/restart.txt, percebam na tarefa restart.

Acima adicionamos nosso arquivo database.yml em nossa pasta shared então precisamos adicioná-la dentro do release corrente após o deploy, a tarefa database faz exatamente isso.

Na tarefa permissions setamos as permissões necessárias para pasta public.

Depois, resolvemos o problemas de aquivos de imagens adicionados pelos usuários (podemos supor um cadastro de produtos). As tarefas dentro de assets criam uma pasta upload dentro de shared e um link simbólico em public/imagens apontando para esta pasta.

Por fim vamos executar o tão esperado deploy.

bash
1
2
cap deploy:cold
cap deploy

Rodamos o cap deploy:cold primeiro para colocar os arquivos no servido, depois efetuamos o deploy.
A partir da segunda implantação não é necessário rodar cap deploy:cold
Se precisar migrar seu banco utilize cap deploy:migrations
Alguma coisa fugiu do controle? volte ao release anterior com cap deploy:rollback
Para mais informações cap -T para visualizar todas as tarefas do Capistrano.

Juntando tudo

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Projeto
set :application, "app_rails"       # O nome do projeto
set :keep_releases, 5               # Isso guardar os 5 últimos deploys
set :rails_env,     "production"    # O ambiente em que o Rails irá atuar

# SCM
set :scm, 'git'
set :repository,  "git@github.com:LeandroSNunes/app_rails.git"
set :branch, 'master'
set :deploy_via, :remote_cache

# Servidor
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
set :user, "leandro"
set :use_sudo, false
server "leandronunes.com.br", :web, :app, :db, :primary => true
set :deploy_to, "/www/app_rails.leandronunes.com.br/#{application}"

#Tarefas
namespace :deploy do
#   task :start do ; end
#   task :stop do ; end
   task :restart, :roles => :app, :except => { :no_release => true } do
     run "touch #{current_path}/tmp/restart.txt"
   end
   task :database, :roles => :app do
     run "cp #{deploy_to}/#{shared_dir}/database.yml #{release_path}/config/"
   end
   task :permission, :roles => [:web, :db, :app] do
     run "chmod 755 #{release_path}/public -R"
   end
end

namespace :assets do
    task :symlink, :roles => :app do
      assets.create_dir
        run <<-CMD
         rm -rf  #{release_path}/public/images/upload &&
         ln -nfs #{shared_path}/upload #{release_path}/public/images/upload
       CMD
    end
      task :create_dir, :roles => :app do
        run "mkdir -p #{shared_path}/upload"
      end
end

after "deploy:assets:symlink", 'deploy:database'
after "deploy:update_code", 'deploy:permission'

Então…

Isso foi minha colheita em um dia de deploy aqui na empresa e basicamente quando for efetuar um deploy da sua aplicação você vai estar neste ciclo novamente:

  • Adicionar seu último release em um repositório
  • Iniciar o monitoramento do Capistrano no diretório de sua aplicação
  • Editar o arquivo de configuração do Capistrano
  • Fazer um confere das configurações no servidor
  • Montar a estrutura de pastas no servidor
  • Fazer deploy de sua aplicação
  • Configurar o ambiente de produção
  • Cruzar os dedos e atualizar seu navegador

Algumas informações tive acesso dando umas googladas e dois blogs que usei de referências foram Unix and Me e Objetiva, acessem para visualizarem o conteúdo completo.

Para mais informações https://github.com/capistrano/capistrano/wiki/_pages

Commentários