Child pages
  • Automating Application Deployment with Capistrano (Overview)

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Changed links to the correct site, because the old one is about UK gambling now

...

Here is the official Capistrano installation instructon instruction page: httphttps://www.capify.org/installcapistranorb.com/documentation/getting-started/installation/. On Leopard all you need to do is to run the following command with root privileges:

No Format

gem install -y capistrano

...

Basics of using Capistrano are well described on its official site:http https://www.capify.org/getting-started/basicscapistranorb.com

Writing simple deployment recipe

...

So let's start our recipe file:

Code Block

task :deploy, roles => :app do
end

This is the empty definition of task "deploy" that will run on application servers (see, roles :app). We need to define the :app role in order to make the recipe usable:

Code Block

role :app, "localhost"
task :deploy, roles => :app do
end

Ok - this is not much, but at least something. Capistrano recipes are executed using "cap" command. So now you should be able to execute the following:

No Format

cap -f BugTracker.cap deploy

The output should be:

No Format

  * executing `deploy'

Now let's fill our recipe with some real code. Basically the simplest (not usable in production, but good as example) way of deploying is:

...

This step should be done locally - we don't need to use Capistrano's main feature of executing ssh-commands in parallel on multiple servers.
So the code will be:

Code Block

system "tar -C build -czvf BugTracker.woa.tar.gz BugTracker.woa"
raise "failed to create an archive" unless $?.exitstatus == 0

...

Here's how it can be done:

Code Block

upload "BugTracker.woa.tar.gz", "/tmp/BugTracker.woa.tar.gz"

...

This will look like this:

Code Block

run "rm -rf /Library/WebObjects/Applications/BugTracker.woa"

...

Nothing new in this code:

Code Block

run "tar -C /Library/WebObjects/Applications -xzvf /tmp/BugTracker.woa.tar.gz"

So, right now we have the following deployment script:

Code Block

role :app, "localhost"
task :deploy, roles => :app do
  # creating BugTracker.woa.tar.gz
  system "tar -C build -czvf BugTracker.woa.tar.gz BugTracker.woa"
  raise "failed to create an archive" unless $?.exitstatus == 0

  # copy the BugTracker.woa.tar.gz to remote server
  upload "BugTracker.woa.tar.gz", "/tmp/BugTracker.woa.tar.gz"

  # remove previous /Library/WebObjects/Applications/BugTracker.woa
  run "rm -rf /Library/WebObjects/Applications/BugTracker.woa"

  # unpack /tmp/BugTracker.woa.tar.gz to /Library/WebObjects/Applications"
  run "tar -C /Library/WebObjects/Applications -xzvf /tmp/BugTracker.woa.tar.gz"
end

...

Let's write a cleanup task in order not to leave tar.gz archives both on our local machine and on remote servers. The task can look like this:

Code Block

task :cleanup, roles => :app do
  FileUtils.rm_f "BugTracker.woa.tar.gz"
  
  run "rm -f /tmp/BugTracker.woa.tar.gz"
end

The new part here is FileUtils.rm_f call. This is the way to delete files in ruby.
Now we can check that :cleanup task actually works by executing the following command:

No Format

cap -f BugTracker.cap cleanup

It's great to have a cleanup task, but it would be even better if it would run after the deployment. Capistrano has a "hooks" feature that will help us with that:

Code Block

after :deploy, :cleanup

Yes, that's all. Now if :deploy tasks finishes successfully :cleanup task will be executed automatically.

...

You can use variable in capistrano scripts. You can set then with the "set" command:

No Format

set <variable name>, <variable value> - this commands says for itself. Some examples:
Code Block

set "var1", "some data"
set :var2, 10

Note also that you can use the identifiers starting with ":" as variable names. This is the ruby way of specifying unique identifiers (called symbols in ruby). Using symbols is a bit faster than using strings, besides you can easily see identifiers in your code, as they won't be quoted - and will not look like string literals. Anyway these calls are absolutely equal:

Code Block

set :var1, "some data"
set "var1", "some data"

After the variable is set, you can use it in string literals using in the traditional ruby way:

Code Block

run "echo #{var1}"
run "echo #{var2}"

So let's generalize our script with some variables usage:

Code Block

role :app, "localhost"

set :app_name, "BugTracker.woa"
set :archive_name, "#{app_name}.tar.gz"
set :tmp_archive_path, "/tmp/#{archive_name}"
set :wo_apps_path, "/Library/WebObjects/Applications"
set :app_path, "#{wo_apps_path}/#{app_name}"

task :deploy, roles => :app do
  # creating BugTracker.woa.tar.gz
  system "tar -C build -czvf #{archive_name} #{app_name}"
  raise "failed to create an archive" unless $?.exitstatus == 0

  # copy the BugTracker.woa.tar.gz to remote server
  upload archive_name, tmp_archive_path

  # remove previous /Library/WebObjects/Applications/BugTracker.woa
  run "rm -rf #{app_path}"

  # unpack /tmp/BugTracker.woa.tar.gz to /Library/WebObjects/Applications"
  run "tar -C #{wo_apps_path} -xzvf #{tmp_archive_path}"
end

task :cleanup, roles => :app do
  FileUtils.rm_f archive_name

  run "rm -f #{tmp_archive_path}"
end
after :deploy, :cleanup

...