Background

The viuGraph team has write some portion of backend API. We want to deploy the API that written on Ruby on Rails to the cloud, so our mobile app engineer can test their app.

We are an agile team, so we will deploy updates frequently. Deploying an app with FTP is a cumbersome method and risky. Someone who deploy new updates may make a mistake or make the system fail. So we need another best practice of deployment method.

Problem Definition

What is the best practice to deploy a Ruby on Rails app?

Deployer

After read some Google search results, I have pick some options:

  1. Chef
  2. Puppet
  3. Capistrano
  4. Fabric

Chef & Puppet

I think Chef is a promising solution. I have try Chef Solo and Chef Server. It is great. We can define what to do on Recipe and Cookbook, and we can define our cloud infrastructure as code (Infrastructure as a Code). The syntax is clean because Chef using Ruby DSL (Domain Specific Language). But I think Chef only suitable for viuGraph when we have a lot of servers to manage. Thats apply too for Puppet.

Capistrano & Fabric

Okay lets look to Capistrano & Fabric. They are simple deployer that using SSH connection and Shell command to do their jobs. We can define task such as:

  1. update NGINX and Puma configuraion
  2. pull latest source code from GitHub
  3. trigger database migration
  4. trigger database seed
  5. restart NGINX and Puma

The different of two is Capistrano written in Ruby, Fabric in Python.

Choose the deployer

Chef & Puppet is too much for viuGraph now. We only have small count on server instance at current time. Then I have to choose Capistrano or Fabric. viuGraph backend API written on Ruby on Rails, so I think Capistrano is the best choice because my team don’t need to learn Python just for deployment.

Capistrano configuration sample for Ruby on Rails 5

You can start using Capistrano by add this line to your Gemfile:

gem 'capistrano'

Then install the gem by this command:

bundle install

After that you can add configuration by execute this command:

cap init

Capistrano will add these necessary configuration file:

 config
 |- deploy.rb
 |- deploy
    |- production.rb
    |- staging.rb

You will write down general configuration at config/deploy.rb file; and you will write additional configuration for specific environments such as production and staging.

Here sample of deploy.rb file:

set :application, 'core'
set :repo_url, 'git@github.com:viugraph/viugraph.git'
set :branch, 'master'

set :linked_files, fetch(:linked_files, []).push('config/puma.rb')
set :linked_dirs, fetch(:linked_dirs, []).push('log')

set :puma_threads, [0, 16]
set :puma_workers, 0
set :puma_conf, "#{shared_path}/config/puma.rb"

namespace :deploy do
  desc 'Restart sidekiq on worker server.'
  task :restart_sidekiq do
    on roles(:worker) do
      execute 'systemctl stop sidekiq'
      execute 'systemctl start sidekiq'
    end
  end

  before 'check:linked_files', 'puma:config'
  before 'check:linked_files', 'puma:nginx_config'
  after 'puma:smart_restart', 'nginx:restart'
  after 'nginx:restart', 'deploy:restart_sidekiq'
end

And here sample of staging.rb file that define specific configuration for staging envinronment:

set :linked_files, fetch(:linked_files, []).push('config/secrets.yml')

server '10.100.1.88', 
  user: 'root', 
  roles: %w(app db web)

server '10.100.1.99', 
  user: 'root', 
  roles: %w(app web worker)

Conclusion

After do due dilligence, I choose Capistrano as deployer of viuGraph backend API. It is simple but powerful for small number of cloud server instance. Also it was written on Ruby; so we will not blocked to learn new programming language only to deploy a Ruby on Rails app (if we use Fabric).

Capistrano can do the job nicely. Just initialize configuration files, adjust general configuration and then adjust configuration for specific environment.