Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you do a rolling deploy with capistrano?

We have 2 instances behind a load balancer running the same rails app with passenger. When we deploy, the server startup time causes requests to timeout. As a result we have a script that updates each webserver individually by taking one off the LB, deploying with cap, testing a dynamic page load, putting it back on the LB.

How can we get capistrano to do this for us with one command? I have been able to set it up to deploy to all instances simultaneously but they all restart at the same time and cause the site to be unavailable for 20 seconds.

What am I missing here? Seems like this should be a common pattern.

like image 638
chrishomer Avatar asked Nov 04 '22 15:11

chrishomer


1 Answers

It's not actually that straightforward to serialize deployment in capistrano, which likes to parallelize all of its operations between servers. To restate the issue, it seems like you have a handful of servers and want to take each one offline in sequence to update the deployment.

The trick is to override the deploy:create_symlink task in your deployment configuration:

def perform_task_offline options
  sudo "take_this_server_offline", options
  yield
  sudo "put_this_server_online", options
end

def create_symlink_task options
  # does what your existing deploy:create_symlink did, something like:
  run "rm -f /web/current && ln -s #{release_path} /web/current", options
end

namespace :deploy do

  task :create_symlink, {once: true, except: {no_release: true}} do
    deployed_servers = Array.new

    roles[:app].servers.each do |current_server|
      options = {hosts: current_server}
      deployed_servers.push current_server
      perform_task_offline(options) { create_symlink_task options }
    end
  end
end

In this case perform_task_offline includes commands that execute on the server specified in options that remove it from the load balancer while it yields the block including create_symlink_task, which creates the deployment symlink.

You should then be able to run the standard cap command to deploy, and you'll see the servers sequentially go offline, create the "current" symlink, then come back up.

Note that the above code tracks the servers that have successfully been deployed to with deployed_servers. If you want to be able to rollback an active failed deployment (that is, the failure happens during deployment itself) on only the servers that had previously been deployed to, you'll need a similar loop inside of an on_rollback do block, but over only the deployed_servers.

like image 95
ringmaster Avatar answered Nov 09 '22 10:11

ringmaster