After playing around with Phing for a while I decided to bring the simplicity of Capistrano – which I have been using with my Rails apps – to our Zend Framework project at work. Surprisingly it wasn’t hard at all.
“Capistrano is a tool for automating tasks on one or more remote servers”. That’s straight off their website and this tool rocks.
Capistrano is written in Ruby and needs the ruby library to be installed on the client machine. It does not need ruby on the production or any other target servers and at work we deploy from two machines and needed ruby installed on just the two. However the ruby files for the deployment recipes need to be in source control along with the rest of the code.
The following resources came in useful while we were setting up:
- Slicehost.com Ruby on Rails article – Setting up Ruby and Rubygems
- Using Capistrano with PHP
I use Ubuntu at work and the following steps are what we had to do to get Capistrano working on Ubuntu 8.04 but should work on most distros.
Step 1: Installing Ruby and Ruby gems
Install ruby packages
sudo aptitude install ruby1.8-dev ruby1.8 ri1.8 rdoc1.8 irb1.8 libreadline-ruby1.8 libruby1.8 libopenssl-ruby
Create some symlinks from the ruby install to their locations
sudo ln -s /usr/bin/ruby1.8 /usr/bin/ruby sudo ln -s /usr/bin/ri1.8 /usr/bin/ri sudo ln -s /usr/bin/rdoc1.8 /usr/bin/rdoc sudo ln -s /usr/bin/irb1.8 /usr/bin/irb
Make sure subversion is installed
svn --version
If not installed, install it. You could of course use another source control system. Git seems to be the new hotness.
sudo apt-get install subversion
Install rubygems from source
mkdir ~/sources cd ~/sources w get http://rubyforge.org/frs/download.php/56227/rubygems-1.3.3.tgz tar xzvf rubygems-1.3.3.tgz cd rubygems-1.3.3 sudo ruby setup.rb
Create a symlink for rubygems and update it
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem sudo gem update sudo gem update --system
Install capistrano, capistrano multi-stage and echoe gems
sudo gem install capistrano sudo gem install capistrano-ext sudo gem install echoe
That’s it. The Ruby environment is all set up.
Step 2: Creating the deploy file
Change to the root directory of your application, create a ‘config’ folder if you dont have one and type
capify .
Capistrano creates two files. A ‘Capfile’ for loading the deploy script and the deploy script itself. Open up the Capfile and remove the line where it tries to load plugins. This is specific to the Rails framework.
The Capfile should now look like this:
load 'deploy' if respond_to?(:namespace) load 'config/deploy'
Open up the deploy.rb file created in the config folder and edit it for your setup.
The various configuration parameters are available on the Webistrano website. Our sample recipe is further down the page.
Step 3: Add multistage
For deploying to multiple environments, the capistrano multistage extension needs to be added. We usually have a staging, integration and a production stage and I’ll assume that here.
For multi-stage, the capistrano-ext gem needs to be included, the various stages specified and the default stage set. Furthermore, all configuration parameters not common to all stages need to be taken out of the deploy .rb file.
Create a deploy folder in the config directory and add a file for each of your environment. In our case we have production.rb, integration.rb and staging.rb files.
Add the environment specific parameters to these files.
Our sample deploy.rb file looks like:
set :stages, %w(staging integration production) set :default_stage, "staging" require 'capistrano/ext/multistage' set :application, "app" ############################################################# # Settings ############################################################# default_run_options[:pty] = true set :use_sudo, false ############################################################# # Servers ############################################################# set :user, "username" set :domain, "example.com" set :port, 22 server domain, :app, :web role :db, domain, :primary => true ############################################################# # Subversion ############################################################# set :repository, "http://example.com/svn/#{application}/trunk" set :scm_username, "svn-user" set :scm_password, "svn-pass" set :deploy_via, :export ############################################################# # Tasks ############################################################# after :deploy, 'deploy:cleanup' # overide Rails specific tasks here. desc "Do nothing" deploy.task :restart, :roles => :app do # do nothing. php deploys don't need a server restart end deploy.task :migrate, :roles => :app do # migrate task is rails specific end
Our staging deploy file sample (APPROOT/config/deploy/staging.rb)
set :deploy_to, "/path/to/staging"
If your staging and production environments are on different servers you obviously need to move the ‘Servers’ section to the individual deploy files.
Step 4: Setup and do initial deploy
The first step is to setup the server for Capistrano. Capistrano has a command to do this but due to the way it works, the application will be deployed to a folder called ‘current’ (really just a symlink to the latest release) within your ‘deploy_to’ directory. This means the document root (for apache virtualhost) will be in /path/to/staging/current/public rather than /path/to/staging/public and your apache (or nginx, etc.) config has to be changed to reflect this.
Commit the files to subversion (insert your SCM here) then type:
cap deploy:setup
This command creates two directories in your deploy_to path, releases and shared. The releases directory stores versions of the application as they are deployed. The”after :deploy, ‘deploy:cleanup’” line in the recipe cleans up this folder by keeping just the latest 5 (by default) releases. The ‘shared’ folder is for storing images and other files that are not part of your application and are therefore not under source control.
To deploy your app, run:
cap deploy
This deploys to the default stage – staging in our case.
To deploy to production you’d type:
cap deploy production
It’s as easy as that. This is obviously not specific to the Zend Framework and can be used with any app.
Related posts: