Legacy Deploy with Capistrano
So, you’re on a rescue project with some legacy code (and by “legacy” I almost always mean PHP). The old developer probably just FTP’ed changes up to the server. You could do the same, but frankly that fills me with dread. On a good day I don’t like deploys. What if something goes wrong?!?!?! To help me to relax, I use good tools that let me trust my deploy and allow me to rollback if something doesn’t work.
In a Rails project you’d get that security from Capistrano. Turns out that’s the right tool for you legacy project as well. Capistrano 2 had a few, easily addressed, Rails-centric tasks. However, Capistrano 3 is framework agnostic by default. (Am I implying PHP is a framework? No, I am not.) First, you want the code under some for of software revision control, specifically Git. If your project has nothing, put it under Git:
cd the-project
git init
git add .
git commit -m 'Initial commit'
If it’s under SVN, convert the repository to Git, here’s a lovely tutorial. Something else? Convert it to Git.
(Actually, Capistrano 3 does have some support for SVN and other SCMs though not as front and center as Capistrano 2 did. You’re own your own for the configuration details.)
In the root of your project create a Gemfile:
source 'https://rubygems.org'
group :development do
gem 'capistrano'
end
Then bundle install
. Once the bundle finishes, run cap
install
. This will set up the Capfile, cap tasks, and config
files. For a Rails project you might need to tweak the Capfile to
enable support for bundler, assets, etc. However, for our legacy
deploy we need none of that.
What we do need to do is edit the configs, config/deploy.rb, config/deploy/production.rb, config/deploy/staging.rb.
In deploy.rb you’ll want to set the application name, the URL of your repo, and the deploy directory:
set :application, 'legacy_app'
set :repo_url, 'git@github.com:me/legacy_app.git'
All that staging.rb and/or production.rb need are the remote host and user to deploy to. You can just use the app role:
server 'example.com', user: 'me', roles: %w{app}
However, if you are deploying to the same server for staging and production, also override the deploy path (which defaults to “/var/www/application”) for at least one stage lest one clobber the other:
set :deploy_to, "/var/www/#{fetch(:application)}_staging"
After that it’s as simple as cap staging deploy
or cap production
deploy
!
Just as it would with Rails, Capistrano will deploy in to
“current” in the deploy directory. You’ll likely need to tweak your
web server config or symlink the current document root to the
current directory. Definitely worth it, as this is what gives you
cap production deploy:rollback
.
Also as with Rails, you can add additional tasks that run a various points in the deploy. For example, if you needed to clear the Varnish cache you could put the following in lib/capistrano/tasks/varnish.rake
namespace :varnish do
desc 'Clear Varnish cache'
task :clear_cache do
on roles(:app) do
execute "varnishadm 'ban.url .'"
end
end
end
and add:
namespace :deploy do
after :published, 'varnish:clear_cache'
end
to your config/deploy.rb
There’s a good intro to using hooks to run your own tasks here. I clear cache the after the new code has been published, but there are plenty of other points in the deploy where tasks can run. A full list of what fires when can be found in http://capistranorb.com/documentation/getting-started/flow/
With a setup like this you can quickly deploy a new version of whatever mess you inherited and, more importantly, roll it back with a single command. I’m feeling more relaxed already. Sorry about the PHP.
Comments