Capistrano is the tool typically used to deploy Ruby applications. It is not however the best option when deploying software in the cloud.
Do not take me wrong. Capistrano is a great tool. It works very well when deploying an application to a small number of servers with the static IP addresses, e.g. when staging and production environments consist of dedicated servers. Deploying in the cloud however creates some unique deployment challenges:
- Servers may go down and the new servers launched to replace them will run on different hardware with a different set of IP addresses.
- You may want to set up a dynamically scalable server array where servers are added and terminated automatically based on the application load.
To address these challenges you need a self-contained deployment process which gets an application running on a server upon launch without manual intervention such as release master fiddling with the IP addresses or running ‘cap deploy’.
Our Setup
We are running a set of servers on Amazon including a dynamically scalable array of EC2 application servers. In building our infrastructure we leveraged RightScale which adds a management layer on top of the Amazon services. Using RightScale you can create server templates which combine Amazon machine images (AMIs) with a set of configurable scripts (RighScripts) which for example can be invoked on server launch. To make it even easier, they have a fairly comprehensive set of pre-built server templates.
To build our application server template we started with a RightScale template and substantially modified it to suit our needs. On launch, at a high level, our servers run the following sequence of scripts:
- Install SSH keys
- Install Ruby
- Install Nginx/Passenger
- Create application directory structure
- Install and configure git
- Checkout application code from github
- Create database.yml file
- Install gems
- Install monitoring agents
- Start delayed_job
- Connect application to the load balancers
For example a script to create database.yml file looks like that:
#!/bin/bash -ex # Create database.yml for a Ruby on Rails application # Storing database.yml in a source code control system with its production database credentials creates a security risk. # Using this script, you can take advantage of the RightScale's secure credentials store and generate the file when an application server is launched. # If this is a reboot skip this script if test "$RS_REBOOT" = "true" ; then logger -t RightScale "Skip RB create database.yml." exit 0 fi # Create database.yml file cat webapps/$APPLICATION/shared/system/config/database.yml $RAILS_ENV: adapter: mysql2 host: $MASTER_DB_DNSNAME port: 3306 encoding: utf8 reconnect: false database: $DB_SCHEMA_NAME pool: 5 username: $DBAPPLICATION_USER password: $DBAPPLICATION_PASSWORD EOF ln -nfs /home/webapps/$APPLICATION/shared/system/config/database.yml /home/webapps/$APPLICATION/current/config/database.yml logger -t RightScale "database.yml created."
The script is also available at https://gist.github.com/1132976.
Summary
When deploying Ruby applications in the cloud, you need an ability for servers to fully bootstrap themselves – including getting an application up and running. Rather than using Capistrano, you may want to develop a set of scripts to execute the application deployment tasks automatically, as part of the server launch sequence.
You’re describing a pull type deployment, I agree that is the more scaleable solution…
I did a little more in-depth comparison of the two models in the “ruby cloud” space: http://mikemainguy.blogspot.com/2011/08/push-versus-pull-deployment-models.html