Rubaidhstrano started out as Graeme Matheison’s collection of deployment-related stuff. This version collects his recipes together with some of my own, and bakes in my opinions instead of his.
There’s a real mish-mash of stuff in here, so let’s take it one at a time.
We’ve supplied a bunch of sensible defaults to required options:
-
We use Git, GitHub, make heavy use of submodules and (almost) always name our repository after the application name. That means we can guess a number of things, which is nice.
-
We use Passenger for deployment, nobody needs to do any sudoing and, by default everything runs on a single host.
-
We use jammit for asset compression by default (you can also switch to
the embedded yuicompressor if you prefer).
-
Check for all the possible (default) ssh keys, and forward our ssh-agent to the remote machine. This means you can clone the repository from GitHub using your own SSH key instead of a shared deployment one.
Of course, these defaults are supplied in such a way that they can easily be overridden if they don’t suit a particular application; just replace their values.
There is a mixture of Capistrano and Rake tasks to allow the database on the deployment environment to be backed up, downloaded and restored into another environment. These tasks work with either MySQL or PostgreSQL databases.
There are a few useful use cases for these tasks.
In order to automatically back up the production database before a migration, insert the following into your capistrano recipe:
set :backup_database_before_migrations, true
This is done in the defaults anyway, so should be enabled by default, so if you want to disable it, you can do:
set :backup_database_before_migrations, false
You’ve got a problem in production that you suspect is down to data rather than anything else and you’d like to dump the production database to your local development environment for further testing. This can be achieved with:
cap production db:download rake db:backup:load
Note: this example assumes that you’re using multistage deployments for staging and production. Please also be aware that this will nuke your current development environment’s database!
We’ve been through a few deployment strategies over the years – using mongrels managed by Runit or Solaris SMF. Now we’re just using Passenger inside Apache and life is much easier. :-) If you’ve also seen the light then you can switch Capistrano to use the Passenger deployment strategy with one line:
set :daemon_strategy, :passenger
Of course, the defaults already set this, so you probably don’t need to worry about it. :-)
The code for the multistage deployment has largely been borrowed from the capistrano-ext gem by Jamis Buck. It’s been modified here so that it doesn’t bother anyone unless you want a multistage deployment. If you do want a multistage deployment, create files named after each of the stages in config/deploy
(for example, create config/deploy/staging.rb
and config/deploy/production.rb
to have a staging and production deployment). Those files should configure things that are special to that particular deployment, while config/deploy.rb
will still configure the generic setup. Anything in one of the staging files will override a setting in the generic setup.
Once you’ve configured multistage deployments, you’ll have to prefix every deployment command with the name of the environment you want to deploy to. For example, to deploy to the production cluster:
cap production deploy
or to the staging environment:
cap staging deploy
By default, if you set up staging, we assume that you want to deploy from a branch named after the stage, and with a rails_env named after the stage. So, for example, when you do:
cap staging deploy
we assume that you want to deploy from the ‘staging’ branch and that the running rails environment will be ‘staging’ too. You can, of course, change this. :)
Automatically run New Relic’s post-deployment task if it’s there. Don’t bother if it’s not.
Some of our applications have assets that need to be shared across deployments. The most common example is if you’ve been using attachment_fu (or some other upload plugin which stores files locally in the filesystem) and you want to maintain those uploads between deployments.
In order to share assets between deployments, list the directories needing shared as so:
set :asset_directories, ['public/paintings', 'public/pdfs']
Each directory is relative to RAILS_ROOT
.
Its also common to keep some configuration files only on the production server, and to re-link them at each deployment. For example, you might manage your database.yml out of band, so it’s not in your git repo. By default we’ll re-link the database.yml; just override the :config_files setting to change this:
set(:config_files) {{"#{latest_release}/config/database.yml" => "#{shared_path}/config/database.yml"}}
If you want to, and have the bandwidth, you can duplicate the production shared assets to your local environment. You can achieve that with:
cap production assets:download rake assets:backup:load
If you combine the two duplication tasks, you get a complete mechanism to replicate a deployment environment back to your local system. So the combination exists. To duplicate your production environment to your development environment, run the following:
cap production replicate
A few things to be aware of, though:
-
This will nuke the data from your development environment, including the database and anything stored in asset directories. Don’t say I didn’t warn you!
-
It doesn’t scale. If the data in your production database, along with its assets is large, it ain’t going to work well. I’m currently getting mildly irritated with it on an application with a combined set of assets which is only 50MB.
-
There may be security or data protection issues with duplicating your production environment to your laptop. Please make sure that you are complying with data protection laws and the stringent security practices of your company.
Rails provides the ability to vendor all your gems. Some gems are C extensions. If you have chosen to vendor all your C extension-based gems then you’ll need to build them each time you deploy. If that’s the case, you can:
set :build_gems, true
and they will automatically be built. In fact, we like this option, so it’s switched on by default. If you wish to disable it in a particular deployment, add the following to your config/deploy.rb
:
set :build_gems, false
Every time a release happens, a tag will be created in your local git repository with the release name (which, by default, is of the format stage-release-yyyymmddhhmmss, eg production-release-20090522054102) and pushes that tag out (nothing else, though, I hope!). If you want to disable this behaviour, do:
set :tag_on_deploy, false
and it’ll quit noising up your GitHub feed.
Ever waste your time deploying because you’d committed changes but not pushed them back to the origin repo? No more. Just add this to your deployment recipe:
before "deploy", "deploy:check_revision"
Similarly, you can protect yourself from forgetting to run migrations after deployment with this task:
after "deploy:symlink", "db:notify_if_pending_migrations"
If you use the whenever
gem to manage your cron jobs as versioned code, you can update the server cron file on deploy:
after "deploy:symlink", "cron:update"
If you use the db-populate
gem to handle seed data, you might find these tasks helpful:
after "deploy:finalize_update", "db:populate" after 'deploy:finalize_update', 'db:migrate_and_populate'
There are also cap tasks for two other common database operations:
db:migrate db:reset_sequences
Background task management via the delayed_job
gem is also simple:
set :enable_delayed_job, :true
This depends on having monit on the server to manage the delayed_job daemon.
Set a reminder to be shown on next deployment:
reminders:add
Show all current reminders:
reminders:show
Clear all reminders:
reminders:clear
By default, reminders are shown and cleared after any deployment. You can define a reminder_host role to determine which server(s) reminders are stored on.
Thanks to Graeme Mathieson for the original rubaidhstrano.
Some of the code has been borrowed from other sources. The multistage deployment code was borrowed from the capistrano-ext gem by Jamis Buck. Thanks, Jamis! (Oh, and PS, thanks for Capistrano, too!)
Craig Webster’s simple_deployment provided inspiration for the asset backup, and I’m pretty sure Craig fixed a number of issues in this plugin’s previous incarnation, rubaidh_platform
. Thanks, Craig!
Thanks to Kevin Triplett for some Rails 3 fixes and ideas.
Reminders tasks originally from github.com/bokmann/dunce-cap.
Copyright © 2010-2011 Lark Group, Inc., released under the MIT license Portions copyright © 2009 Rubaidh Ltd, released under the MIT license