¿Qué es Capistrano?

Capistrano es una herramienta que nos permite automatizar nuestros deploy, o sea subir nuestro proyecto a un servidor y también nuestras actualizaciones.

Capistrano tiene tareas y herramientas que nos permiten:

  • precompilar assets
  • reiniciar el server
  • Migrar la base de datos
  • Además podemos agregarle tareas nuevas

Antes de empezar, necesitamos tener un servidor donde podamos hacer el deploy, en este tutorial puedes aprender a construir uno con Nginx, RVM y postgreSQL. Nginx lo configuraremos junto con Puma.

Otra detalle que necesitamos es un proyecto en Rails (el que vamos a subir) y una cuenta en bitbucket o github desde esté nuestro proyecto.

Paso 1: Instalando la gema Capistrano

Dentro de tu computador, en la carpeta del proyecto, agregaremos las gemas de capistrano.  Para eso abriremos el archivo gemfile y agregaremos las gemas.

group :development do
  gem 'capistrano', require: false
  gem 'capistrano-bundler', require: false
  gem 'capistrano-rails', require: false
  gem 'capistrano-rvm', github: 'capistrano/rvm', require: false
  gem 'capistrano-ssh-doctor', require: false
end

y luego en el terminal dentro de la misma carpeta del proyecto:

bundle

Paso 2: Instalación de Capistrano

Con Capistrano, dentro de nuestra misma carpeta del proyecto crearemos los archivos para hacer el setup

cap install

Al hacerlo veremos lo siguiente:

create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified

Paso 2.1 Configuración del Capfile

En el archivo Capfile debemos especificar los requerimientos de nuestro setup, el que viene por defecto es genérico para distintas necesidades y aquí agregaremos que necesitamos herramientas para puma y rvm. Para lograrlo agregaremos al principio del archivo lo siguiente, debemos revisar si algún require queda duplicado y removerlo.

require 'capistrano/setup'
require 'capistrano/deploy'
require 'capistrano/rails'
require 'capistrano/bundler'
require 'capistrano/rvm'
require 'capistrano/puma'
require 'capistrano/ssh_doctor'

require "capistrano/scm/git"

install_plugin Capistrano::SCM::Git

# Tambien agregaremos plugins que nos permitan configurar Puma

install_plugin Capistrano::Puma # Default puma tasks
install_plugin Capistrano::Puma::Workers  # if you want to control the workers (in cluster mode)
install_plugin Capistrano::Puma::Jungle # if you need the jungle tasks
install_plugin Capistrano::Puma::Monit  # if you need the monit tasks
install_plugin Capistrano::Puma::Nginx  # if you want to upload a nginx site template

Paso 2.2 Configuración del archivo de deployment

El archivo config/deploy.rb contiene información como de donde se obtendrá el proyecto ejemplo github, bitbucket y también información para conectarse al servidor, por lo mismo tenemos que configurarlo config/deploy.rb.

# config valid only for Capistrano 3.1
lock '~> 3.11.0'

set :application, 'nombre_app'
set :repo_url, 'repositorio github o bitbucket' 

set :scm, :git
set :branch, "master"
set :deploy_via, :copy
set :user, 'deploy'

# Default deploy_to directory is /var/www/my_app
set :deploy_to, '/home/deploy/nombre_app'
set :linked_files, %w{config/database.yml}
set :linked_dirs, %w{bin log tmp/pids tmp/cache tmp/sockets vendor/bundle public/system}

namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      execute :touch, release_path.join('tmp/restart.txt')
    end
  end

  after :publishing, 'deploy:restart'
  after :finishing, 'deploy:cleanup'
end


namespace :deploy do
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      # Your restart mechanism here, for example:
      # execute :touch, release_path.join('tmp/restart.txt')
    end
  end

  after :publishing, :restart

  after :restart, :clear_cache do
    on roles(:web), in: :groups, limit: 3, wait: 10 do
      # Here we can do anything such as:
      # within release_path do
      #   execute :rake, 'cache:clear'
      # end
    end
  end

end

Advertencia: En la sección donde dice lock hay que ocupar la versión correspondiente de la gema de capistrano. Para saber la versión instalada puedes utilizar bundle show

donde dice nombre_app hay que utilizar el nombre de la aplicación.

donde dice repo_url debes poner la dirección ssh del git de tu aplicación

donde dice branch debes poner el branch que quieres ocupar para deployment, los más comunes son master, deploy y capistrano.

donde dice user: deploy es el nombre del usuario para hacer deployment, si seguiste el tutorial sobre como montar un servidor con nginx y passenger entonces tendrás a deploy como usuario.

donde dice deploy_to debemos poner el path hasta el usuario junto con el nombre de la app, por ejemplo si nuestra app se llama desafiolatam sería:

set :deploy_to, '/home/deploy/desafiolatam'

Paso 2.3 Configuración del archivo de producción

Otro archivo que nos falta modificar es el de config/deploy/production.rb, en este vamos a especificar donde está la aplicación y la base de datos.

role :app, %w{[email protected]}
role :web, %w{[email protected]}
role :db,  %w{[email protected]}

server '127.0.0.1', user: 'deploy', roles: %w{web app}, my_property: :my_value
set :stage, :production

aquí lo que hay que cambiar es deploy por el nombre del usuario de deployment (sólo si usaste uno distinto) y el ip del servidor. el resto se deja como está.

Paso 3: Generación de la clave ssh

hacemos ssh a la máquina del servidor con:

ssh deploy@ip-de-la-maquina

dentro de la máquina buscamos si tenemos una clave generada, ¿cómo lo hacemos? entramos a la carpeta del usuario.

cd

revisamos si tenemos la carpeta .ssh y dentro el archivo id_rsa.pub, sólo en caso de que no tengamos algunas de las dos anteriores.

ssh-keygen -t rsa

ahora vamos a mostrar la clave generada y la vamos a copiar

cat /home/deploy/.ssh/id_rsa.pub

el texto copiado (completo, incluyendo el email que muestra) lo vamos a pegar en bitbucket (o github).

para agregar la clave vamos a bitbucket seleccionamos el proyecto, clickeamos en settings, luego en deployment keys y luego en add key y ahí agregamos la clave ssh de la máquina.

Paso 4: Revisando ssh

dentro de la carpeta de nuestro proyecto con capistrano (en nuestra máquina).

bundle exec cap production ssh:doctor

si hay algún error es porque hicimos uno de los pasos anteriores mal, habrá que buscar el error en internet y revisar bien los pasos, uno bastante posible es que hayamos copiado mal la clave del servidor.

Paso 5: configurando puma

Nginx ocupa el mismo sistema de virtual hosts que apache

para eso ocupa dos carpetas /etc/nginx/sites-available y /etc/nginx/sites-enable

cuando uno empieza a crear uno nuevo lo pone sites-available y cuando lo quiere activar lo copia a través de un link simbólico a sites enable

ln -s ruta_completa_al_site_available ruta_destino

Nota: Editar el contenido del link simbólico o del original causa el mismo efecto.

Sin embargo nosotros estamos trabajando con el archivo default, este virtual host ya viene copiado, por lo que no tenemos que hacer nada, la explicación anterior es exclusivamente para cuando queremos poner más de una aplicación de rails en nuestro sitio.

paso 10.1 Configurando el virtual host por default

El siguiente paso consiste en editar el archivo /etc/nginx/sites-available/default

sudo vim /etc/nginx/sites-available/default

puedes comentar el contenido que existe actualmente para no perderlo, o puedes incluso hacerle una copia, pero lo importante es que dentro del archivo vaya el siguiente contenido.

server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;
        server_name mydomain.com;
        passenger_enabled on;
        rails_env    production;
        root         /home/deploy/nombre_proyecto/current/public;
        # redirect server error pages to the static page /50x.html
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
}

donde dice nombre_proyecto debe ir el nombre de la carpeta de tu proyecto.

donde dice mydomain.com debería el nombre de tu dominio comprado en nic chile o godaddy, sin embargo como es nuestro virtual host por default también será capaz de responder a la ip, en ese caso simplemente no ponemos la directiva server_name.

para hacer valer los cambios:

sudo service nginx restart

si hay un fallo en el archivo es posible revisar los logs de nginx con

sudo tail -n 50 /var/log/nginx/error.log

tail te muestra las últimas n lineas, 50 es el n, puedes también ocupar cat, pero a medida que crezca el log se va demorar más.

finalmente lo que tenemos que hacer es copiar nuestra app corriendo de rails a nombre_proyecto/current

ahora, ¿Por qué ocupar una carpeta llamada current, porque en la siguiente tutorial vamos a aprender a hacer deployment automatizado con Capistrano.

paso 5: cap deploy

dentro del bash en la carpeta de nuestro proyecto

cap production deploy

Advertencia fallará, pero eso es normal. Vamos a tener un error del tipo: ERROR linked file /home/deploy/nombre_app/shared/config/database.yml does not exist on 104.236.105.133

Paso 5.1 Configurando el database.yml

hay dos formas de manejar esta situación, una de ellas es crear el archivo en el computador y subirlo por scp o ftp, pero la mejor forma es crearlo directamente en la máquina remota con vim o nano (u otro editor)

vim /home/deploy/nombre_app/shared/config/database.yml

dentro del archivo tenemos que poner como mínimo los siguientes parámetros:

production:
  host: localhost
  adapter: postgresql
  encoding: unicode
  database: el_nombre_de_tu_bd
  pool: 5
  username: el_usuario_de_tu_bd
  password: el_password_de_tu_bd

Paso 5.2 Instalando el runtime de javascript

Si hacemos deploy en este momento probablemente fallará en el servidor por culpa del runtime de javascript el cual probablemente no estará instalado, una de las formas más fáciles de instalar es con:

apt-get install nodejs

Paso 6: Segundo deploy

volvemos a nuestra máquina y corremos nuevamente

cap production deploy

Paso 6.1 Configurando el archivo secret.yml

Entra a la ip del server y deberías poder ver tu app.

Si a esta altura falla, lo que hay que hacer es revisar los logs de nginx, uno de los errors más comunes es haber olvidado setear dentro de tu app la clave secreta para producción dentro del archivo de tu proyecto de rails llamado config/secrets.yml

para arreglar eso vamos utilizar cualquier editor (vim, nano, etc) a e el archivo config/secret.yml

vim config/secret.yml

dentro del archivo:

production:
  secret_key_base:
    codigo_random_inventado

el código random inventando puede ser como cualquiera de los secret_key_base que tienes en tu proyecto local pero con algunas variantes introducidas por ti.

Paso 7: la tercera es la vencida

ahora si que al entrar al servidor deberíamos poder ver nuestra app, si todavía falla hay que revisar los logs, lo más importantes son el nginx y el de rails, el de nginx se encuentra en etc/nginx/error.log y los de rails se encuentran dentro de /home/deploy/nombre_app/log/production.log