===== Publicando aplicação rails em produção usando Ubuntu + Rails 4 + Nginx + Unicorn + PostgreSQL + Capistrano =====
Entre na máquina via ssh
$ ssh usuario@app_name.ifce.edu.br
Obs: Caso a chave ssh do servidor tenha sido alterada, por algum motivo específico, remova o arquivo known_hosts:
rm ~/.ssh/known_hosts
==== Criando usuário da aplicação ====
É recomendado criar um usuário na máquina com o mesmo nome da aplicação, caso o mesmo ainda não exista. Não é interessante utilizar um usuário genérico para configurar o deploy. Nesse tutorial iremos utilizar o usuário como exemplo: minha_app. Troque esse nome pelo nome da sua aplicação ou qualquer outro nome que achar mais conveniente.
Crie o usuário
sudo adduser minha_app
Digite a senha e as informações necessárias até finalizar o processo
Adicione o usuário ao arquivo sudoers:
sudo visudo
No final do arquivo adicione:
minha_app ALL=(ALL) NOPASSWD:ALL
Digite Ctrl + O para salvar e depois Ctrl + X para fechar o arquivo
Logue com esse novo usuário
su minha_app
==== Adicione sua chave ssh ao servidor para se logar sem senha: ====
Dê ssh para alguma máquina a fim de criar o diretório ~/.ssh
ssh usuario@app_name.ifce.edu.br
Dê um Ctrl+C ao ser solicitado pela senha.
Adicione sua chave ao arquivo ~/.ssh/authorized_keys
Na sua máquina local pegue a sua chave ssh se existir com o comando (Cuidado para não copiar os espaços):
cat ~/.ssh/id_rsa.pub
No servidor adicione a chave ao arquivo:
vim ~/.ssh/authorized_keys
Cole conteúdo da chave nesse arquivo
Salve e teste
==== Instalando o RVM ====
**Instalando o Curl**
$ sudo apt-get update
$ sudo apt-get install curl
Obs: caso tenha algum problema ao baixar o rvm, verifique os seus servidores DNS no arquivo: /etc/resolv.conf. Sugestão: adicione os servidores de DNS do google: 8.8.8.8 e 8.8.4.4
$ curl -L get.rvm.io | bash -s stable
Caso ocorra o seguinte erro, rode o comando sugerido pelo próprio erro:
GPG signature verification failed for '/home/app_name/.rvm/archives/rvm-1.27.0.tgz' - 'https://github.com/rvm/rvm/releases/download/1.27.0/1.27.0.tar.gz.asc'!
try downloading the signatures:
Rode:
command curl -sSL https://rvm.io/mpapis.asc | gpg --import -
E depois rode novamente os comandos abaixo para finalizar a instalação do rvm:
$ curl -L get.rvm.io | bash -s stable
Agora é preciso instalar os requisitos para instalar o ruby e instalar também a gem bundles para gerenciar as outras gems do projeto:
$ source ~/.rvm/scripts/rvm
$ rvm requirements
$ rvm install 2.0.0 (Utilize a versão que vc estiver trabalhando no projeto atual)
$ rvm use 2.0.0 --default
$ rvm rubygems current
$ gem install bundler
==== Instale a lib de dependência do PostgreSQL, Imagemagick e Git ====
$ sudo apt-get install libpq-dev imagemagick git-core
Crie o usuário do postgresql da forma que você preferir
Crie o Banco de Dados do Sistema no Postgresql
==== Instalando e configurando o Nginx ====
$ sudo apt-get install nginx
$ nginx -h
$ cat /etc/init.d/nginx
$ /etc/init.d/nginx -h
$ sudo service nginx start
$ sudo service nginx status (Ele deve estar rodando agora!)
Crie o arquivo nginx.conf no diretório config do seu projeto rails:
upstream unicorn {
server unix:/tmp/unicorn.app_name.sock fail_timeout=0;
}
server {
listen 80 default_server deferred;
root /opt/apps/app_name/current/public; (Escolha o diretório em vermelho com carinho de acordo com a partição que está montada no sistema. Sugestão: rode df -h)
location ^~ /assets/ {
gzip_static on;
expires max;
add_header Cache-Control public;
}
try_files $uri/index.html $uri @unicorn;
location @unicorn {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://unicorn;
}
error_page 500 502 503 504 /500.html;
client_max_body_size 20M;
keepalive_timeout 120;
}
Adicione a gem do Unicorn ao projeto. Adicione a seguinte linha no arquivo Gemfile:
gem 'unicorn'
Crie a configuração do unicorn em config/unicorn.rb
root = "/opt/apps/app_name/current"
working_directory root
pid "#{root}/tmp/pids/unicorn.pid"
stderr_path "#{root}/log/unicorn.log"
stdout_path "#{root}/log/unicorn.log"
worker_processes Integer(ENV['WEB_CONCURRENCY'])
timeout 30
preload_app true
listen '/tmp/unicorn.app_name.sock', backlog: 64
before_fork do |server, worker|
Signal.trap 'TERM' do
puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
Process.kill 'QUIT', Process.pid
end
defined?(ActiveRecord::Base) and
ActiveRecord::Base.connection.disconnect!
end
after_fork do |server, worker|
Signal.trap 'TERM' do
puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
end
defined?(ActiveRecord::Base) and
ActiveRecord::Base.establish_connection
end
# Force the bundler gemfile environment variable to
# reference the capistrano "current" symlink
before_exec do |_|
ENV['BUNDLE_GEMFILE'] = File.join(root, 'Gemfile')
end
Crie o arquivo config/unicorn_init.sh.erb
#!/bin/sh
set -e
# when to timeout a request, a lower value limits the risk that
# a long running process will block all connections
TIMEOUT=${TIMEOUT-60}
# the path to the app, dynamically populate from the capistrano
# definition
APP_ROOT=/opt/apps/<%= application %>/current
# where we're going to store unicorns pid file, must match what is
# specified in unicorn.rb.erb
PID=$APP_ROOT/tmp/pids/unicorn.pid
CMD="cd $APP_ROOT; bundle exec unicorn -D -c $APP_ROOT/config/unicorn.rb -E <%= rails_env %>"
AS_USER=deploy
set -u
OLD_PIN="$PID.oldbin"
sig () {
test -s "$PID" && kill -$1 `cat $PID`
}
oldsig () {
test -s $OLD_PIN && kill -$1 `cat $OLD_PIN`
}
workersig () {
workerpid="$APP_ROOT/tmp/pids/unicorn.$2.pid"
test -s "$workerpid" && kill -$1 `cat $workerpid`
}
run () {
if [ "$(id -un)" = "$AS_USER" ]; then
eval $1
else
su -c "$1" - $AS_USER
fi
}
case "$1" in
start)
sig 0 && echo >&2 "Already running" && exit 0
run "$CMD"
;;
stop)
sig QUIT && exit 0
echo >&2 "Not running"
;;
force-stop)
sig TERM && exit 0
echo >&2 "Not running"
;;
kill_worker)
workersig QUIT $2 && exit 0
echo >&2 "Worker not running"
;;
restart|reload)
sig USR2 && echo reloaded OK && exit 0
echo >&2 "Couldn't reload, starting '$CMD' instead"
run "$CMD"
;;
upgrade)
if sig USR2 && sleep 2 && sig 0 && oldsig QUIT
then
n=$TIMEOUT
while test -s $OLD_PIN && test $n -ge 0
do
printf '.' && sleep 1 && n=$(( $n - 1 ))
done
echo
if test $n -lt 0 && test -s $OLD_PIN
then
echo >&2 "$OLD_PIN still exists after $TIMEOUT seconds"
exit 1
fi
exit 0
fi
echo >&2 "Couldn't upgrade, starting '$CMD' instead"
run "$CMD"
;;
reopen-logs)
sig USR1
;;
*)
echo >&2 "Usage: $0 "
exit 1
;;
esac
Adicione a gem do capistrano ao projeto:
$ vim Gemfile
group :development do
gem 'capistrano-rails'
gem 'capistrano-rvm'
gem 'capistrano3-unicorn'
end
Instale a gem do Capistrano
$ bundle exec cap install
Atualize o arquivo do Capistrano: Capfile, na raiz do projeto:
require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rvm'
require 'capistrano/bundler'
require 'capistrano/rails/assets'
require 'capistrano/rails/migrations'
require 'capistrano3/unicorn'
load 'deploy'
load 'config/deploy' # remove this line to skip loading any of the default tasks
# Load custom tasks from `lib/capistrano/tasks' if you have any defined
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
Atualize o arquivo de Deploy em: config/deploy.rb
set :stages, %w(production staging)
set :default_stage, "staging"
require 'capistrano/ext/multistage'
set :whenever_command, "bundle exec whenever"
set :whenever_environment, defer { stage }
# require "whenever/capistrano"
set :application, "app_name"
set :user, "caio"
set :port, 22
set :deploy_via, :remote_cache
set :use_sudo, false
set :keep_releases, 1
set :scm, "git"
set :repository, "git@gitlab.ifce.edu.br:dgti/app_name.git"
set(:deploy_to) { "/home/#{user}/web/#{rails_env}" }
default_run_options[:pty] = true
ssh_options[:forward_agent] = true
# simple method to create a file from an erb template. Used
# to generate dynamic configuration files.
def template(from, to)
erb = File.read(from)
put ERB.new(erb).result(binding), to
end
**Crie os arquivos do seu(s) ambiente(s) no diretório config/deploy
Observar exemplo dos arquivos de outros sistemas.**
==== Gere e Adicione a chave ssh do servidor no repositório git remoto (no caso o gitlab do ifce)
Entre no diretório do ssh: ====
cd ~/.ssh && ls
Verifique se o arquivo **id_rsa.pub** já existe. Caso não existe você deve criá-lo com o seguinte comando:
ssh-keygen -t rsa -C "app_name@ifce.edu.br"
Apenas fique apertando Enter nos prompts que serão exibidos. Não precisa digitar nada.
Agora você precisa copiar o conteúdo da chave pública: **id_rsa.pub** para o repositório git (no caso o gitlab do ifce)
Vá no Projeto > Settings > Deploy Keys e crie uma nova, colando o conteúdo da chave no campo Key.
==== Checagem de deploy ====
$ cap production deploy:check
==== Bootstrap de deploy (criação da estrutura de diretórios inicial) ====
cap staging deploy:setup
==== Configurações finais de deploy ====
* Adicione a configuração do ambiente correspondente (production ou staging) ao arquivo:
/opt/apps/app_name/shared/config/database.yml
* Dê permissões para o arquivo de inicialização do unicorn
chmod +x /opt/apps/app_name/shared/config/unicorn_init.sh
* Remova o site padrão do nginx
sudo rm /etc/nginx/sites-enabled/default
* Reinicie o nginx
sudo service nginx restart
* Deploy
$ cap production deploy