Jim Cheung

Capistrano

Install

on ubuntu 14, just sudo apt-get install capistrano

Setup Target Server

setup a deploy user:

sudo adduser deploy
sudo adduser deploy sudo
su deploy

then ssh-copy-id deploy@remote-host to setup ssh connection

Structure

root path is defined by :deploy_to, then structure is like this:

├── current -> /var/www/my_app_name/releases/20150120114500/
├── releases
│   ├── 20150080072500
│   ├── 20150090083000
│   ├── 20150100093500
│   ├── 20150110104000
│   └── 20150120114500
├── repo
│   └── <VCS related data>
├── revisions.log
└── shared
└── <linked_files and linked_dirs>

Configuration

variables can be either global or stage:

set variable

set :application, 'value'
# or lambda
set :application, -> { "SomeThing_#{fetch :other_config}" }

get variable

fetch :application
fetch(:special_thing, 'some_default_value') 

see here for list of pre-defined variables.

Initialize

$ cd my-project
$ capify .

looks like this:

├── Capfile
├── config
│   ├── deploy
│   │   ├── production.rb
│   │   └── staging.rb
│   └── deploy.rb
└── lib
└── capistrano
└── tasks

Capfile will automatically include any tasks from *.rake files in lib/capistrano/tasks.

configuration

create a config/deploy/staging.rb

Capistrano breaks down common tasks into a notion of roles, for example web, app, and db.

set :stage, :staging

# ==================

Supports bulk-adding hosts to roles, the primary

server in each group is considered to be the first

unless any hosts have the primary property set.

role :app, %w{example.com} role :web, %w{example.com} role :db, %w{example.com}

# Extended Server Syntax
# ======================
# This can be used to drop a more detailed server
# definition into the server list. The second argument
# is something that quacks like a hash and can be used
# to set extended properties on the server.
server 'example.com', roles: %w{web app}, my_property: :my_value

Servers can be defined in two ways, implicitly using the simple role syntax and explicitly using the extended server syntax.

for more specific ssh parameters:

# using simple syntax
role :web, %w{hello@world.com example.com:1234}
# using extended syntax (which is equivalent)
server 'world.com', roles: [:web], user: 'hello'
server 'example.com', roles: [:web], port: 1234

The deploy.rb is a place where the configuration common to each environment can be specified, normally the repository URL and the user as whom to deploy are specified here.

set :application, 'rails3-bootstrap-devise-cancan-demo'
set :repo_url, 'https://github.com/capistrano/rails3-bootstrap-devise-cancan'
set :branch, 'master'

Tasks

server 'example.com', roles: [:web, :app]
server 'example.org', roles: [:db, :workers]
desc "Report Uptimes"
task :uptime do
  on roles(:all) do |host|
    execute :any_command, "with args", :here, "and here"
    info "Host #{host} (#{host.roles.to_a.join(', ')}):\t#{capture(:uptime)}"
  end
end

local tasks

replace on with run_locally:

desc 'Notify service of deployment'
task :notify do
  run_locally do
    with rails_env: :development do
      rake 'service:notify'
    end
  end
end

Before / After Hooks

# call an existing task
before :starting, :ensure_user

after :finishing, :notify


# or define in block
before :starting, :ensure_user do
  #
end

after :finishing, :notify do
  #
end

other way to call other tasks is to use invoke():

namespace :example do
  task :one do
    on roles(:all) { info "One" }
  end
  task :two do
    invoke "example:one"
    on roles(:all) { info "Two" }
  end
end