Rails Capistrano Deployment

  28 Oct 2016


Getting your project live online may invole some mundane tasks. You might need to upload your codebase, amend configurations and execute the same commands over and over again.

In this article, I will use Capistrano, it is the task-automation-tool, to solve the above problem So that we will only have to run capistrano tasks and continue learning how to automate the process of deployments and updates using Capistrano.

Capistrano is very good suit for Ruby on Rails app. So, we are going to do server setup that is running CentOS 7.2 and deploy Ruby on Rails app on it.

Initial new Rails app by rails new testapp and go into project directory cd testapp

An overview about starting capistrano project is we are required to modify at least these following 4 files:

  1. Gemefile
  2. Capfile
  3. config/deploy/production.rb (or other stage files)
  4. config/deploy.rb

Here is the step in details in order to initial and modify related capistrano files in our application. And in this example we will use rbenv and puma to run the app. So, let’s start:

  1. Add this 3 gems in to Gemfile:

     gem 'capistrano-rbenv'
     gem 'capistrano3-puma', github: "seuros/capistrano-puma"
    

and run bundle install

  1. Create capistrano files by running bundle exec cap install. Then, edit the Capfile and it should look like this (require rbenv and puma):

     require "capistrano/setup"
     require "capistrano/deploy"
    
     require 'capistrano/rbenv'
     require 'capistrano/puma'
    
     Dir.glob("lib/capistrano/tasks/*.rake").each { |r| import r }
    
  2. Add the following content in config/deploy/production.rb, modify server IP and user as needed:

     server '111.222.35.30', user: 'cap', roles: %w{app web}
     set :pty, true
     set :ssh_options, {
       forward_agent: true,
       auth_methods: ["publickey"]
     }
    
  3. Also, add the following content in config/deploy.rb, modify application, repo_url and config puma setting as needed:

     set :application, 'testapp'
     set :repo_url, 'git@github.com:zdk/testapp.git'
    
     set :puma_bind, "tcp://0.0.0.0:4000"
     set :puma_threads, [4, 8]
     set :puma_workers, 4
    
     namespace :puma do
       desc 'Create Directories for Puma Pids and Socket'
       task :make_dirs do
         on roles(:app) do
           execute "mkdir #{shared_path}/tmp/sockets -p"
           execute "mkdir #{shared_path}/tmp/pids -p"
         end
       end
    
       before :start, :make_dirs
     end
    

You can see that we also added cap task named make_dirs. To list all available commands, we list it with -T option or bundle exec cap -T.

  • Now we can create share sockets and pids directories on the server using make_dirs task

      $ bundle exec cap production puma:make_dirs
      00:00 puma:make_dirs
            01 mkdir /home/user/apps/testapp/shared/tmp/sockets -p
          ✔ 01 cap@111.222.35.30 0.798s
            02 mkdir /home/cap/apps/testapp/shared/tmp/pids -p
          ✔ 02 cap@111.222.35.30 0.491s
    
  • Upload puma config file to the server

      $ bundle exec cap production puma:config
      00:00 puma:config
            Uploading /home/cap/apps/testapp/shared/puma.rb 100.0%
    
  • And deploy to the server

      $ bundle exec cap production deploy
    
          00:00 git:wrapper
                01 mkdir -p /tmp
              ✔ 01 cap@111.222.35.30 0.452s
                Uploading /tmp/git-ssh-testapp-production-di.sh 100.0%
                02 chmod 700 /tmp/git-ssh-testapp-production-di.sh
              ✔ 02 cap@111.222.35.30 0.086s
          00:00 git:check
                01 git ls-remote --heads git@github.com:zdk/testapp.git
                01 0ab881c2edb9b8ae9d95d7a49ba324b212fc4d90	refs/heads/master
              ✔ 01 cap@111.222.35.30 0.352s
          00:01 deploy:check:directories
                01 mkdir -p /home/cap/apps/testapp/shared /home/cap/apps/testapp/releases
              ✔ 01 cap@111.222.35.30 0.086s
          00:01 deploy:check:linked_dirs
                01 mkdir -p /home/cap/apps/testapp/shared/log /home/cap/apps/testapp/shared/tmp/pids /home/cap/apps/testapp/shared/tmp/cache /home/cap/apps/testapp/shared/t…
              ✔ 01 cap@111.222.35.30 0.086s
          00:01 nginx:create_log_paths
                01 sudo mkdir -pv /home/cap/apps/testapp/shared/log
              ✔ 01 cap@111.222.35.30 0.092s
          00:01 git:clone
                The repository mirror is at /home/cap/apps/testapp/repo
          00:01 git:update
                01 git remote update --prune
                01 Fetching origin
              ✔ 01 cap@111.222.35.30 0.301s
          00:02 git:create_release
                01 mkdir -p /home/cap/apps/testapp/releases/20161028043451
              ✔ 01 cap@111.222.35.30 0.087s
                02 git archive master | tar -x -f - -C /home/cap/apps/testapp/releases/20161028043451
              ✔ 02 cap@111.222.35.30 0.093s
          00:02 git:set_current_revision
                01 echo "0ab881c2edb9b8ae9d95d7a49ba324b212fc4d90" >> REVISION
              ✔ 01 cap@111.222.35.30 0.088s
          00:02 deploy:symlink:linked_dirs
                01 mkdir -p /home/cap/apps/testapp/releases/20161028043451 /home/cap/apps/testapp/releases/20161028043451/tmp /home/cap/apps/testapp/releases/20161028043451/public
              ✔ 01 cap@111.222.35.30 0.086s
                02 rm -rf /home/cap/apps/testapp/releases/20161028043451/log
              ✔ 02 cap@111.222.35.30 0.086s
                03 ln -s /home/cap/apps/testapp/shared/log /home/cap/apps/testapp/releases/20161028043451/log
              ✔ 03 cap@111.222.35.30 0.087s
                04 ln -s /home/cap/apps/testapp/shared/tmp/pids /home/cap/apps/testapp/releases/20161028043451/tmp/pids
              ✔ 04 cap@111.222.35.30 0.086s
                05 ln -s /home/cap/apps/testapp/shared/tmp/cache /home/cap/apps/testapp/releases/20161028043451/tmp/cache
              ✔ 05 cap@111.222.35.30 0.086s
                06 ln -s /home/cap/apps/testapp/shared/tmp/sockets /home/cap/apps/testapp/releases/20161028043451/tmp/sockets
              ✔ 06 cap@111.222.35.30 0.087s
                07 ln -s /home/cap/apps/testapp/shared/public/system /home/cap/apps/testapp/releases/20161028043451/public/system
              ✔ 07 cap@111.222.35.30 0.088s
          00:04 bundler:install
                01 RBENV_ROOT=$HOME/.rbenv RBENV_VERSION=2.3.1 $HOME/.rbenv/bin/rbenv exec bundle install --path /home/cap/apps/testapp/shared/bundle --without development test --deployment --quiet
              ✔ 01 cap@111.222.35.30 2.516s
          00:07 deploy:symlink:release
                01 ln -s /home/cap/apps/testapp/releases/20161028043451 /home/cap/apps/testapp/releases/current
              ✔ 01 cap@111.222.35.30 0.086s
                02 mv /home/cap/apps/testapp/releases/current /home/cap/apps/testapp
              ✔ 02 cap@111.222.35.30 0.087s
          00:07 deploy:cleanup
                Keeping 5 of 6 deployed releases on 111.222.35.30
                01 rm -rf /home/cap/apps/testapp/releases/20161027105323
              ✔ 01 cap@111.222.35.30 0.088s
          00:07 deploy:log_revision
                01 echo "Branch master (at 0ab881c2edb9b8ae9d95d7a49ba324b212fc4d90) deployed as release 20161028043451 by di" >> /home/cap/apps/testapp/revisions.log
              ✔ 01 cap@111.222.35.30 0.086s
          00:08 puma:phased-restart
                01 bundle exec pumactl -S /home/cap/apps/testapp/shared/tmp/pids/puma.state -F /home/cap/apps/testapp/shared/puma.rb phased-restart
                01 Command phased-restart sent success
                01
              ✔ 01 cap@111.222.35.30 0.450s
    

Now we should have puma application server running on the server. If you ssh into the server eg. ssh cap@111.222.35.30 and check running processes.

$ ps aux |grep puma
cap 12721  0.0  1.6 201508 16668 ?        Sl   Oct27   0:04 puma 3.6.0 (tcp://0.0.0.0:3000) [20161027114024]
cap 17633  0.1  6.3 835120 64232 ?        Sl   04:35   0:01 puma: cluster worker 0: 12721 [20161027114024]
cap 17637  0.1  6.2 835308 64068 ?        Sl   04:35   0:01 puma: cluster worker 1: 12721 [20161027114024]
cap 17650  0.1  6.2 835260 64060 ?        Sl   04:35   0:01 puma: cluster worker 2: 12721 [20161027114024]
cap 17663  0.1  6.3 835196 64304 ?        Sl   04:35   0:01 puma: cluster worker 3: 12721 [20161027114024]

We can see that our puma application server is running and listening on port 3000 So, we are mostly finish we can access the app with http://111.222.35.30:3000

In this article, I want to make it simply run puma. But for production, we may want to do reverse proxy via Nginx, then we can use https://github.com/platanus/capistrano3-nginx

You can see that setting up Capistrano is fairly easy.

comments powered by Disqus