Upgrading from Capistrano 2 to 3

Updated . Posted . Visible to the public.

Capistrano 3 is a major rework of the framework and requires several adjustments to your deploy configuration files. The biggest change is that they moved away from their custom DSL and use Rake instead. For connecting with and operating on the servers, they bring a new gem SSHKit which does the heavy lifting. It's SSHKit's DSL that is used anywhere inside the Rake tasks. See #Resources at the bottom for examples.

Step 1: Upgrade guide

For migration from 2 to 3, follow this tutorial: Capistrano 3 Upgrade Guide Show archive.org snapshot .

Step 2: More changes

  • Task syntax has changed.

    desc 'Run script'
    task :script, roles: :app, only: { primary: true } do
      run "cd #{current_path} && RAILS_ENV=#{rails_env} bundle exec rails runner 'ScriptRunner.go'"
    end
    

    becomes

    desc 'Run script'
    task :script do
      on primary :app do
        within current_path do
          with rails_env: fetch(:rails_env, 'production') do
            execute :bundle, 'exec', "rails runner 'ScriptRunner.go'"
          end
        end
      end
    end
    
  • There is no :user setting any more. Set the deploy user directly as an option to the server directive. Also, the roles syntax has become more ruby'esque, and the first server will by default be the primary one:

    server 'staging.example.com', user: <user here>, roles: %w(app web db)
    
  • The organization of Capistrano files has changed. It seems the deploy.rb and deploy/*.rb files are only meant for configuration, i.e. many calls to set :<variable>, <value>. Custom tasks should live in lib/capistrano/tasks/*.rake.

  • The deploy:restart task is not automatically run any more! If you need it to run, add an after hook:

    after 'deploy:published', 'deploy:restart'
    
  • To run code on the servers, you need to use execute instead of run. Caution: When a command passed to execute contains white space, it is run in the home directory instead of the directory you might have specified with within(...) do. I would call that a bug, but the core team disagrees Show archive.org snapshot . Basically, execute and capture commands behave like Ruby's system etc. methods. Just call them with separate arguments, e.g. execute :dumple, '--fail-gently'.

  • Hooks have changed:

    deploy:update_code -> deploy:updating
    
  • Invocation of other tasks has changed:

    # old:
    namespace.task
    # new:
    invoke 'namespace:task'
    
  • shared/system is now shared/public/system! See this card. This is already handled for our own projects.

Configuration that is not needed any more

set :copy_exclude, ['.git']

The .git repository is excluded from the current directory on the server, but its contents live in the repo directory on the server.

set :allow_sudo, false

Capistrano does no sudo any more.

requiring capistrano/rvm or similar

Error messages

When trying to deploy with Capistrano 3 using your old Capistrano 2 config files, you'll get many error messages that are giving no hint about what really is wrong. The solution to most of them is to strictly hold to the new task syntax.

undefined method `instance' for Capistrano::Configuration:Class

undefined local variable or method `ssh_options' for main:Object

Use the new syntax instead:

set :ssh_options, { ... }

wrong number of arguments (1 for 2)

undefined method `tail' for nil:NilClass

You need to wrap your task body in a on ... do ... end block, e.g.

task :dump do
  on primary roles :db do # <-- this
    # perform dump
  end
end

undefined method `map' for :roles:Symbol

You're still using the old task ..., roles: ... syntax, which is not supported any more. Capistrano tasks are Rake tasks now, so you need to specify the roles as shown above (on roles(...) do ... end).

Don't know how to build task 'deploy:update_code'/'deploy:setup'/etc

These error messages may originate from before/after hooks. The Capistrano hooks and deploy tasks have change significantly. See the docs Show archive.org snapshot for what to hook on.

SSHKit::Runner::ExecuteError: Exception while executing on host #SSHKit::Host:0x00005651abfb4bd8: getaddrinfo: Name or service not known

You missed the "server fetcher". Syntax example:

on (roles|primary|release_roles|...) :some_role do 

Resources

Dominik Schöler
Last edit
Dominik Schöler
License
Source code in this card is licensed under the MIT License.
Posted by Dominik Schöler to makandra dev (2015-05-12 14:46)