In this part of the series, I am going to show how we use Capistrano to script our deployments to target environments.

What is Capistrano?
Capistrano is an open source Ruby tool used for deploying web applications. It automates deploying to one or more servers. These deployments can include procedures like placing a war on a target server, database changes, starting services, etc.

A Capistrano script has several major parts

Namespaces: Namespaces in Capistrano are used for differentiating tasks from other tasks with the same name. This is important if you create a library out of your Capistrano deployment configuration, you will want to make sure your tasks are unique. For instance a typical name for a task is setup. You need to make sure that your setup task does not potentially interfere with another user’s custom setup task. By using namespaces, you won’t have this conflict.

Tasks: Tasks are used for performing specific operations. An example task would be setup. Inside the setup task you will generally prepare the server for subsequent steps to execute successfully like deleting the current application.

Variables: Variables in Capistrano are defined as ruby symbols. These are set initially and then referenced later on in the script.

Order of execution: Capistrano allows you to define the order of deployment execution. You do this with Capistrano’s built in feature after. With after you define the order of task execution during your Capistrano deployment.

Templates: Templates are files that have injected ruby snippets. These are used for dynamically building configuration files.

Roles: Roles define what part each server in your infrastructure plays in the deployment. Typical roles consist of db, web and app. Roles are then referenced inside your tasks to determine which server the task is run against.

Since Capistrano is a ruby based tool, you can inject ruby methods and operations to enhance Capistrano. In our deployment we use ruby for returning property values from SimpleDB – as we discussed in part 4 of this series, Dynamic Configuration. This enables us to dynamically deploy to target servers.

How do you install Capistrano?

1. Capistrano is available as a rubygem. You simply type gem install capistrano on your Linux machine (assuming you have ruby and rubygems installed)
2. Type capify . this will create a Capfile which is a main file that Capistrano needs and a config/deploy.rb file (which is your actual Capistrano deployment script).

How do you run a Capistrano script?
You run Capistrano from the command line. From the same directory as your Capfile, type cap namespace:task. namespace and task being your own Namespace and Task defined in your deploy.rb script. This will start your Capistrano deployment.

Why do we use Capistrano?
We use Capistrano in order to have a fully scripted, versioned deployment. Every step in our application deployment is scripted and fully automated – which reduces errors when deploying. This gives us complete control over our deployment and the ability to deploy whenever we are ready.

Capistrano for Manatees
In the Manatee deployment, we use Capistrano for deploying our Manatee tracking application to our target environment. I am going to go through each part of the deploy.rb and explain its use and purpose. In a deployment’s lifecycle, the deployment is run as part of the CD pipeline – discussed in part 2 of the series, CD Pipeline. I’ll first go through a high level summary of the deployment and then dive into more detail in the next section.

1. Variables are set, which includes returning several properties from SimpleDB
2. Roles are set: db, web and app are all set to the ip_address variable configured dynamically in Step #1
3. The order of execution is set to run the tasks in order
4. Tasks are executed
5. If all tasks are executed successfully, Capistrano signals deployment success.

Now that we know at a high level what’s being done during the deployment, lets take a deeper look at the inside of the script. The actual script can be found here: deploy.rb

Variables

Command line setstack – Passed into SimpleDB to return the dynamically set property valuesssh_key – Used by the ssh_options variable to SSH into the target environment

Dynamically setdomain – Used by the application variableartifact_bucket - Used to build the artifact_url variableip_address – Used to define the IP address of the target environment to SSH intodataSourceUsername – Returns a value that is part of the wildtracks_config.properties filedataSourcePassword – Returns a value that is part of the wildtracks_config.properties filedataStorageFtpUsername – Returns a value that is part of the wildtracks_config.properties filedataStorageFtpPassword – Returns a value that is part of the wildtracks_config.properties file

Hardcodeduser – The user to SSH into the target box asuse_sudo – Define whether to prepend every command with sudo or notdeploy_to – Defines the deployment directory on the target environmentartifact – The artifact to deploy to the target serverartifact_url – The URL for downloading the artifactssh_options – Specialized SSH configurationapplication – Used to set the domain that application runs onliquibase_jar – Location of the liquibase.jar on the deployment serverpostgres_jar – Location of the postgres.jar on the deployment server

Roles

Since the app server, web server, and database all co exist on the same environment, we set each of these to the same variable, ip_address.

Namspaces

Deploy: We use deploy as our namespace. Since we aren’t distributing this set of deployment tasks, we don’t need to make a unique namespace. In fact we could remove the namespace all-together, but we wanted to show it being used.
namespace :deploy

Execution

We define our execution order at the bottom of the script using after. This coordinates which task should be run during the deployment.
after "deploy:setup", "deploy:wildtracks_config"
after "deploy:wildtracks_config", "deploy:httpd_conf"
after "deploy:httpd_conf", "deploy:deploy"
after "deploy:deploy", "deploy:liquibase"
after "deploy:deploy", "deploy:restart"

Tasks

Setup: The setup task is our initial task. It makes sure the ownership of our deployment directory is set of tomcat. It then stops httpd and tomcat to get ready for the deployment.
task :setup do
run "sudo chown -R tomcat:tomcat #{deploy_to}"
run "sudo service httpd stop"
run "sudo service tomcat6 stop"
end

wildtracks_config: The wildtracks_config task is the second task to run. It dynamically creates the wildtracks-config.properties file using a template and the variables set previously in the script. It then places the wildtracks-config.properties file on the target environment.
task :wildtracks_config, :roles => :app do

set :dataSourceUsername do
item = sdb.domains["stacks"].items["wildtracks-config"]
item.attributes['dataSourceUsername'].values[0].to_s.chomp
end
set :dataSourcePassword do
item = sdb.domains["stacks"].items["wildtracks-config"]
item.attributes['dataSourcePassword'].values[0].to_s.chomp
end
set :dataStorageFtpUsername do
item = sdb.domains["stacks"].items["wildtracks-config"]
item.attributes['dataStorageFtpUsername'].values[0].to_s.chomp
end
set :dataStorageFtpPassword do
item = sdb.domains["stacks"].items["wildtracks-config"]
item.attributes['dataStorageFtpPassword'].values[0].to_s.chomp
end

set :dataSourceUrl, "jdbc:postgresql://localhost:5432/manatees_wildtrack"
set :dataStorageWorkDir, "/var/tmp/manatees_wildtracks_workdir"
set :dataStorageFtpUrl, "ftp.wildtracks.org"
set :databaseBackupScriptFile, "/usr/share/tomcat6/.sarvatix/manatees/wildtracks/database_backups/script/db_backup.sh"

run "sudo mv /home/ec2-user/httpd.conf /etc/httpd/conf/httpd.conf"
end

Deploy: The deploy task is where the actual deployment of the application code is done. This task removes the current version of the application and downloads the latest.
task :deploy do
run "cd #{deploy_to} && sudo rm -rf wildtracks* && sudo wget #{artifact_url}"
end

Liquibase: The liquibase task sets up and ensures that the database is configured correctly.
task :liquibase, :roles => :db do

set :liquibase_jar, "/usr/share/tomcat6/.grails/1.3.7/projects/Build/plugins/liquibase-1.9.3.6/lib/liquibase-1.9.3.jar"
set :postgres_jar, "/usr/share/tomcat6/.ivy2/cache/postgresql/postgresql/jars/postgresql-8.4-701.jdbc3.jar"

Restart: Lastly the restart task starts the httpd and tomcat services.
task :restart, :roles => :app do
run "sudo service httpd restart"
run "sudo service tomcat6 restart"
end

Now that we’ve gone through the deployment, we need to test it. For testing our deployments, we use Cucumber. Cucumber enables us to do acceptance testing on our deployment. We verify that the application is up and available, the correct services are started and the property files are stored in the right locations.

Capistrano allows us to completely script and version our deployments enabling our deployments to be run at anytime. With Capistrano’s automation in conjunction with Cucumber’s acceptance testing, we are given a high level of confidence in our deployments and that when they are run, the application will be deployed successfully.

In the next and last part of our series – Infrastructure Automation – we’ll go through scripting environment using an industry standard infrastructure automation tool, Puppet.