Deploy with capistrano
Capistrano is a tool from the ruby world normally used to deploy Ruby on Rails applications.
We use this tool to deploy cfml projects to our server farm (4 linux servers for now).
Capistrano connects by ssh to the servers and update the code from the source code system (git, svn...). Each time we deploy, capistrano creates a new directory and move a link named "current" to this new checkout. This default behaviour doesn't work with tomcat, because you can't change the docBase without a restart (this include a link to a directory that is our case), so we point the docBase in the tomcat to a "production" directory and we rsync each time we do a deploy.
Installation
You need to install ruby and the bundler gem.
In the root dir of your project create a Gemfile file with the content:
source 'http://rubygems.org'
gem 'capistrano'
gem 'railsless-deploy'
In the command line:
bundle
This will install the required libs and capistrano itself. It will create another file Gemfile.lock.
Execute in the root project directory:
capify .
This command with create a Capfile file. Add the files Capfile, Gemfile and Gemfile.lock to your source control system.
Configuration
Capistrano Create the file config/deploy.rb with the content:
set :application, "Myproject"
set :repository, "ssh://myuser@mygitserver.com/path/to/git"
default_run_options[:pty] = true
set :scm, :git
set :branch, "master"
set :deploy_via, :remote_cache
set :copy_exclude, ['.git', 'config', 'Gemfile', 'Gemfile.lock']
set :deploy_to, "/var/www/myproject/"
set :keep_releases, 3
set :git_shallow_clone, 1
set :use_sudo, false
desc "Run tasks in production environment"
task :production do
Prompt to make really sure we want to deploy into production
puts "\n\e[0;31m ######################################################################"
puts " #\n # Are you REALLY sure you want to deploy to production?"
puts " #\n # Enter y/N + enter to continue\n #"
puts " ######################################################################\e[0m\n"
proceed = STDIN.gets[0..0] rescue nil
exit unless proceed == 'y' || proceed == 'Y'
set :copy_exclude, ['.git', 'config', 'Gemfile', 'Gemfile.lock', 'lib', 'mxunit', 'test']
role :app, "deploy@prod_ip1", "deploy@prod_ip2", "deploy@prod_ip3", "deploy@prod_ip4"
end
desc "Run tasks in development"
task :devel do
role :app, "deploy@devel_ip1", "deploy@devel_ip2"
end
namespace :deploy do
task :default do
update_code
symlink
rsync_production
end
task :rsync_production do
run "rsync -a --delete #{release_path}/ /var/www/myproject/production/"
cleanup
end
end
Remote server
We need to setup the remote servers. Create the directory /var/www/myproject/ and the user deploy that must have write access to this directory. Also we must install git in the servers.
mkdir -p /var/www/myproject/production
useradd deploy
chown -R deploy /var/www/myproject/
Tomcat
We need to point the docBase in server.xml to the production directory:
<Host name="www.myproject.com" appBase="webapps">
<Context path="" docBase="/var/www/myproject/production" />
</Host>
Setup
In our dev machine we can check that the servers have the required dependencies with:
cap production check
If is all OK, then tell capistrano to setup the remote servers:
cap production setup
It will prompt about if we are sure to deploy in production system, press y and it will ask the deploy password in the servers (must be the same in all servers). Also will prompt for the password of the git user.
Same goes for our development machines just replace production with devel
Now we can deploy our project to the production with the command:
cap production deploy
If all goes well we can see in /var/www/myproject/production/ all our codebase.
Side notes
-
The production server must have access to the git server. Remember that we connect to ssh to the production server and from there we update the code
-
The WEB-INF directory could be problematic: we can create a directory in /var/www/myproject/shared/WEB-INF with write permission to tomcat user:
mkdir /var/www/myproject/shared/WEB-INF
chown tomcat7 /var/www/myproject/shared/WEB-INF
and symlink this directory in the production directory:
ln -s /var/www/myproject/shared/WEB-INF/ /var/www/myproject/production/
- We can deploy other branch, just modify the line in config/deploy.rb:
set :branch, "master"