logo
Published on aidanf.net (http://www.aidanf.net)

Automating remote tasks with capistrano

By aidan
Created 2007-07-23 11:57

Capistrano [1] is a tool for automating tasks on remote machines. Think of it as being like make, ant or rake but targeted for remote tasks. You can use it to automate deployment and management of your remote machines.

It is written in ruby and is widely used for deploying rails applications. Non rubyists often switch off when they hear this. However capistrano is a tremondously powerful tool and can be used to automate and deploy any task on a remote machine - it doesn’t matter what language your application is written in. If you can do something by ssh-ing into a remote machine then you can probably automate it with capistrano. If you manage remote machines or deploy a web application you should check it out - a little time invested in learning capistrano will probably save you a lot of time and effort in the log run.

The standard rails :deploy task shows what you can accomplish with capistrano. This task is used to automate the deployment of a rails application. This task will ssh into each remote machine, export the latest code from your svn server, put this code in a directory structure according to date, create a symbolic link to this directory for the current web deployment and restart the web server. If any part of this process fails, it will be rolled back on all machines. Imagine being able to do this across all your web server machines with a single command.

An example

As an example I will walk through developing a task to backup a remote database to your local machine.

The first thing is to install capistrano. You may need to install ruby and rubygems first if you don’t have them. Check the install instructions [2] from the capistrano site [3]. Next read through the Capistrano Basics [4] page. Now you should be ready to create your own task.

Create a file called Capfile. This where you store your capistrano tasks. When you run capistrano is looks for tasks in a file called Capfile or capfile in the current directory.

Here is the backup task (adapted from here [5]):

role :db, "www.servername.com"
set :user, "aidan"

desc "Backup the remote database to local"
task :backup do
  filename = "/home/aidan/tmp/aidanf_#{Time.now.to_s.gsub(/ /, "_")}.sql.gz"

  on_rollback { run "rm #{filename}" }

  run "mysqldump -u username -p databasename | gzip > #{filename}" do |ch, stream, out|
    ch.send_data "dbpassword\n" if out =~ /^Enter password:/
  end
  `rsync #{user}@#{roles[:db][0].host}:#{filename} /Users/aidan/Backups/web_dbs/`
  run "rm #{filename}"
end

Lets go through this line by line. The line role :db, ... defines the servers we want to access. You can add several servers to this list and tasks will run in parallel on all servers. We can define several roles (e.g. :web, :db, :files) and specify which roles each task runs on. In this case we only need one role. The set :user, ... sets the username to use to login to the remote machine. desc provides a description of the task. task :backup do ... end defines a task called :backup which is our task to backup the remote db to our local machine.

The task starts by constructing the filename and storing in it in a variable. The on_rollback callback lets us define code that will be run if an exception occurs. This allows us to rollback any changes if we encounter a problem. In this case we delete the remote db dump if the task fails.

The run command lets us run a command on the remote machine. In this case we run the mysqldump command to dump the database into our file. We could pass the database password as part of this command but then it would be visible to everyone else using the remote machine. When we call mysqldump with the -p option but without giving it a password it prompts us for the password. ch.send_data sends the password when the output stream from the server asks for it.

Next we run rsync locally to sync the remote database dump to our local machine. Then we delete the database dump from the remote machine.

To run this you should be directory that you saved the Capfile. Run it by calling the cap command with the name of the task you want to execute. Running this gives us:

> cap backup
  * executing `backup'
  * executing "mysqldump -u username -p databasename | gzip> /home/aidan/tmp/aidanf_Fri_Jul_20_15:46:12_IST_2007.sql.gz"
    servers: ["www.servername.com"]
    [www.servername.com] executing command
    command finished
  * executing "rm /home/aidan/tmp/aidanf_Fri_Jul_20_15:46:12_IST_2007.sql.gz"
    servers: ["www.servername.com"]
    [www.servername.com] executing command
    command finished

passwords

When you run capistrano it will establish an ssh connection to each remote machine. To avoid having to enter the password each time you should setup ssh-agent so you can do secure passwordless logins [6].

More info


Source URL:
http://www.aidanf.net/blog/2007/07/23/automating-remote-tasks-capistrano