Small review on using a Capistrano deployment tool

Introduction

Sooner or later each developer understands that project should have a tool for deployment. Small projects developed by only one programmer can deal with it just using Git. It’s simple: you have Git on your production server and pull a necessary branch. Usually, it looks like you pull your code from the master branch into the production environment. So, it isn’t hard to understand that if the code you merged has any errors, you will definitely have the application that doesn’t work in the production. In this case, you make some fixes into the master branch (or directly into the prod).

All of that means that we should think about deployment more seriously. So, let's make an overview of one of the tools that can improve our deployment process. It’s not a tutorial. I want to show you how simple it is to use this tool, and why it is a good practice. We will look at Capistrano features, how Capistrano works, and what benefits we can expect from using Capistrano. 

Small review on using a Capistrano deployment tool 1

What is Capistrano?

Capistrano is a tool for deployment written in Ruby. However, it also can be used to deploy applications written in any other language.

What features make Capistrano a good tool?                           

In general, Capistrano does not require a big set of additional applications on your server. All you need are an ssh connection (probably you'll need to create a new user with the permissions that will be used just for remote management) and Ruby Gems. Also, if we talk about Drupal, we need to say that Capistrano can work with Composer, Drush and bash scripts.

Capistrano works with symlinks

First of all, it means that the release directories created by Capistrano have been already structured and located in one place. Secondly, when you make a roll back to an older release, you just change a link to the directory, that will be set as a Сurrent. Symlinks can be useful for a Drupal application because we can place a private directory outside of the site root.

There is a nice deployment flow (we will talk about it a little bit later) and you don’t need to think about how to structure your scripts, where files and releases will be placed. Just use what has been already made.

Working with multiple stages

This is not just about using a few configurations for the different stages. It is also about parallel tasks execution in a fleet of servers. Tag your servers and let Capistrano give roles to your servers. You will always know where the database server, QA, app server or something else is.

RubyGems package manager

This is a fast and easy way to extend your Capistrano instance. Capistrano has plugins for different frameworks and languages. These plugins provide a set of tasks specific to these platforms. For instance, a Drupal plugin produces an ability to use Drush inside of your tasks and for placing your settings files or private directories outside of the application root.

The repository with all available plugins is here.

Let’s try to install Capistrano and deploy something.

First of all, you need to install Ruby Gems if you don’t have it.

apt-get install ruby rubygems

And next:

gem install Capistrano

After that you need to cd in your project and run it:

cap install .

After that you will have the next structure in your project directory:

├── Capfile

├── config

│ ├── deploy

│ │ ├── production.rb

│ │ └── staging.rb

│ └── deploy.rb

└── lib

└── capistrano

└── tasks

This process is called capifying. After that process, we can edit files deploy.rb and production.rb in the new directories. These files are auto-generated and have comments to simplify your learning. All that you need for our first deployment are an ssh access to a remote server and a repository with our project code. I’ve added a new file development.rb next to production.rb because we always use a few environments.

What benefits can we expect from using Capistrano?

Firstly, we can deploy our application by writing just one console command cap <stage_name> deploy.

Secondly, if something goes wrong, we can rollback the app to the last release by using another one cap <stage_name> rollback.

The third benefit is placing private files outside of root directory. This is also done according to the best practices (as you remember, Drupal core developers never advise web developers to place files in the root directory).

Fourthly, you don’t need to think about routine things, like cache cleaning after deploy or making a database dump before a deploy start. All of that you can paste into your custom scripts. You make it once and forget about it.

How does deployment process look when we use Capistrano?

Before you start writing your configs, you need to understand how Deployment process works.

Deploy flow

When you run a cap production deploy, it invokes the following tasks in a sequence:

  1. deploy:starting 
    - It starts deployment

  2. deploy:started 
     - A hook for your custom tasks

  3. deploy:updating
     - It updates your servers to a new release

  4. deploy:updated 
     - A hook for your custom tasks

  5. deploy:publishing 
     - It publishes the new release

  6. deploy:published
     - A hook for your custom tasks

  7. deploy:finishing
     - It finishes the deployment and run the cleaning up

  8. deploy:finished
     - 
    A hook for your custom tasks

Please, note, that deploy:starteddeploy:updateddeploy:publisheddeploy:finished are the hooks that you must use for adding your own tasks. Capistrano provides you with two ways for that:

after :finishing, 'deploy:cleanup'  #by using before

before :finishing, 'deploy:cleanup' #by using after

That’s all that you need to fire your tasks. You can find a real example in the next chapter.

Rollback flow

When you run a rollback it invokes the same flow with the next tasks in a sequence:

  1. deploy:starting
  2. deploy:started
  3. deploy:reverting
  4. deploy:reverted
  5. deploy:publishing
  6. deploy:published
  7. deploy:finishing_rollback  
  8. deploy:finished

As you can see, the rollback flow shares many tasks with the deploy flow. But note that the rollback flow runs its own: finishing_rollback task because its cleanup process is usually different from the deploy flow.

Author's configs from A live project

File deploy.rb:

# Config valid only for the current version of Capistrano
lock '3.6.0'
#Common params
set :application, 'OurWebsite'
set :log_level, :info

#Environment settings
set :keep_releases, 5
set :stages, %w{development production}

#System Control Management
set :scm, :git
set :repo_url, 'https://name:password@gitlab.com/repo.git'

#Link file settings
set :linked_files, %w{sites/default/settings.php sites/default/default.settings.php}
set :linked_dirs, %w{sites/default/files}

namespace :drupal do
    desc "Backup database"
    task :backupdb do
        on release_roles :app do
            execute "#{deploy_to}/create_development_db_dump.sh"
        end
    end
    desc "Clearing drupal cache (--all)"
    task :cc_all do
        on release_roles :app do
            execute :drush, "-r #{deploy_to}/current cc all"
        end
    end
end

namespace :deploy do
    desc "Backup database before deploy"
    task :before_deploy_backup do
        invoke "drupal:backupdb"
    end
    desc "Clear drupal cache"
    task :after_deploy_cc_all do
        invoke "drupal:cc_all"
    end
    after :finishing, 'deploy:cleanup'
end

File deploy.rb contains general settings. Here we locked a version of Capistrano, set a level of logging, the number of releases that we planned to keep, repository credentials. Also, we’ve created the symlinks to settings files and default/files directory, because we wanted to place them outside of the root directory.

After that, you can see namespaces. Here are 2 namespaces: Drupal and deploy. The first one is the namespace that contains the implementations of our custom tasks related to Drupal. The second one is the namespace that consists of tasks invocation. You just set task you want to fire and from which namespace this task is.

Also, you can see, that when we add our task to the sequence, we use after: for implementing a task after finishing deploy. Two custom tasks are not invoked here because these tasks depend on environments. We plan to fire these tasks only for the specific environments.

File development.rb:

set :stage, :development
role :app, %w{user@192.168.0.1}
set :deploy_to, '/var/www/vhosts/oursite/'

#Repo branch
set :branch, 'develop'

#Deployment
namespace :deploy do
    desc 'change permissions'
    task :change_permissions do
        on roles(:app) do
            execute "cd /var/www/vhosts/oursite/ && chown -R apache:apache ."
        end
    end
    before :check, 'before_deploy_backup'
    after :finishing, 'change_permissions'
end

Here we fired our custom tasks before_deploy_backup and change_permissions. Please note that in the file above (production.rb) we can also implement custom tasks. It is not a strict requirement when it comes to where you write your tasks. You only decide which tasks should be invoked at different stages and place them to a general file if you want to invoke these tasks for a few environments.

All of the above really looks simple.

Conclusion

So, as you can see, using Capistrano isn’t hard. Of course, you need to read docs and learn basic things in Ruby. In this short article, I told you what Capistrano is and how to use it. I hope I showed you that tools like Capistrano are really cool and they can make your developer life easier.

Instead of a long conclusion, I just want to remind you that deployment is the important part of the development process and has its specifics and requirements. All in all, if something can improve our work and save our time – we need to use that.

You might also like