Rails Deployment

As a full-stack web framework, Rails can require some work to deploy an application from the ground up. Rails, unfortunately, has a bad reputation for being hard to deploy, mainly due to problems with the preferred deployment environments when Rails was young (2004–2005). But Rails has grown up, and Mongrel came along in 2006 and made things much easier. There are now good sets of best practices for deploying Rails applications, from the smallest development environments to huge multi-data-center worldwide clusters.

One of the most basic concerns when deploying any web application is scalability: how well the underlying architecture can respond to increased traffic. The canonical Rails answer to the scalability question is shared-nothing(which really means shared-database): design the system so that nearly any bottleneck can be removed by adding hardware. The standard architecture looks like Figure 10-6.

The interface to the application is either a light web server (operating as a reverse proxy balancer[89]) or a hardware load balancer. A small web server is usually used to handle the static files (images, JavaScript, static HTML, stylesheets, and the like) because a single-purpose static file server is much faster than an application server at serving static files. This front end box delegates dynamic requests to one of the appli-cation servers, selected either randomly or based on load.

For redundancy in large setups, two front end servers can be used, on separate machines, proxying to the same set of application servers (see Figure 10-7).

If high availability is required, the load balancers must use a VIP-/VRRP-based solution to ensure that the cluster will always respond to all of its IP addresses even under the failure of one load balancer. If high availability is not a requirement, primitive load balancing will suffice, by giving each load balancer its own IP address and exposing them all through a DNS RR (round-robin) record.

One drawback of this architecture is that once the database becomes the bottleneck, things can get difficult. Database scalability is a hard problem, and we examine this issue in Chapter 4.

The front end web server has several purposes. Depending on the application, these may be mission-critical or not even needed. Consequently, the concrete systems architecture will look very different from application to application. The most common functions of the front end server are the following:

Reverse proxying and load balancing

The front end server balances and distributes requests between the application servers. It also acts as a reverse proxy so that the requests to the application servers appear to be coming from the client, rather than the balancer.

Static file serving

The front end web server (which may or may not be the same software as the load balancer) serves static files much faster than the application servers.

Compression

If HTTP compression is to be used, the front end web server can handle this to reduce CPU load on the application servers.

SSL wrapping

The front end server can handle SSL encryption so that the application server does not have to do it (SSL encryption and decryption are CPU hogs). The front end server usually adds a header such as X-Forwarded_Proto: https to indicate that SSL was used.

Common choices for a front end web server and proxy balancer are as follows.

Apache (http://httpd.apache.org)

Of these servers, Apache is definitely the heaviest. Administrators who have a choice usually select one of the lighter options. But Apache has some advantages: it is well-known and relatively easy to configure, it is very flexible, and it integrates well with its environment.

If you have a choice, use Apache 2.1 or higher, as it supports mod_proxy_ balancer. Otherwise, you will need to proxy to a balancer such as pen or pound in order to load balance between application servers.

Apache can actually directly serve Rails applications over FastCGI, using mod_ fastcgi and the Rails FastCGI dispatcher. However, this approach has mostly been superseded by the reverse-proxy/Mongrel method for new deployments.

Lighttpd (http://www.lighttpd.net)

Lighttpd (usually just pronounced "lighty") is a powerful, light web server. It supports reverse proxying and load balancing with the mod_proxymodule. It is one of the preferred front end servers today.

Like Apache, lighttpd can directly serve Rails with FastCGI. This is still not recommended, as the Mongrel approach is more robust and scalable.

Pen(http://siag.nu/pen/)

Pen is a standalone proxy balancer. It does not serve static files; it only proxies to a list of servers and balances between them.

Pen has SSL-wrapping support. If high availability is needed, Pen can be clustered using the VRRP protocol for failover.

Pound (http://www.apsis.ch/pound/)

Pound is another reverse proxy balancer. Like Pen, it can proxy, balance between servers, and unwrap SSL. It is also not a web server, so you may have to set up a static file server.

However, Pound has some X-Forwarded-For problems when being used as a reverse proxy between Apache and Mongrel,[90] so you should consider Pen instead for this configuration.

nginx (http://nginx.net)

One of the newest but most promising contenders is nginx ("engine X"). Like Apache and lighttpd, nginx is a web server with comprehensive load balancing, rewrite, and proxy features. While the featureset is comparable to Apache, the performance characteristics and memory footprint are more like lighttpd. At the moment, nginx seems to be the best front end for Rails applications.

With the other pieces in place, we now need the biggest piece of the puzzle: the application server that handles all of the dynamic requests. Right now, the best solution is Mongrel.[92]

Prior to Mongrel, Rails applications were best served using the CGI protocol or some variation thereof (FastCGI or SCGI). The basic idea behind this is that the front end web server would talk to the application server using a special protocol, with one connection per request (see Figure 10-8). CGI has the limitation that one new process is created for each request, which is extremely slow for interpreted languages such as Ruby. Therefore, the FastCGI and SCGI protocols were created. They have the advantage that they can work with persistent interpreters—one interpreter can serve many requests over the lifetime of the process. This solution can be scaled by adding more workers.

However, the front end server is still a limiting factor here. The front end server handles every request from start to finish, something we can actually eliminate with a load-balanced setup. In addition, using two different protocols confuses things: the application servers speak FastCGI, and the web servers speak HTTP. To top it off, Apache's mod_fastcgi has had a reputation for crashing after being up for a while.

Enter Mongrel: an HTTP application server. It supports several frameworks, the most prominent being Rails. Instead of having your application servers speak FastCGI, they can natively speak HTTP. This means, among other things, that you can put them behind a hardware or software load balancer, and the dynamic requests may not even need to hit a web server other than Mongrel. Alternatively, you can proxy to them from a web server, as described previously.

Mongrel is very easy to install and control:

	$ sudo gem install mongrel
	$ cd my_rails_app
	$ mongrel_rails start -d

	(mongrel is running as a daemon)

	$ mongrel_rails stop

Mongrel can be run as a service on the Win32 platform, using the mongrel_service gem.

Remember: as an HTTP server, Mongrel will happily serve static files in its docroot, but it will be slower than a server optimized for static files. This is fine in development mode (script/server defaults to Mongrel, even in development mode), but it will be slow in production. For situations where performance matters, set up a front end web server and check the logs to be sure it is serving all of the static assets.

Of course, managing several Mongrels in parallel can get tiring. That's why Bradley Taylor created mongrel_cluster. It is a small library that manages parallel Mongrel application servers. It takes a configuration file, which specifies how many Mongrels to run, with a range of port numbers to expose to the load balancer. The cluster servers can then be started and stopped at once with the simple commands:

	mongrel_rails cluster::start
	mongrel_rails cluster::stop
	mongrel_rails cluster::restart

Once you have a server set up and running smoothly, you need a way to deploy your application from the repository to the server. The naïve process of sshing into the server, updating the code, and restarting the server process gets old very quickly, and it is error-prone.

Enter Capistrano (http://capify.org/): a framework for scripting interaction with remote machines. Capistrano started out as a deployment framework (it was originally called SwitchTower). As people started using it for wider and more varied purposes, it evolved into a general framework for executing commands in parallel on a set of remote servers. In version 2.0, deployment is only a subset of the functionality available through Capistrano, and the deployment tools must be explicitly loaded.

Capistrano, like the rest of Rails, follows the convention over configuration paradigm. In general, the more "mainstream" your situation, the less configuration you will have to write. The framework gives you enough power to do most things you would want to do, but tries to make the simple situations simple.

The Capistrano 2.0 source code is an excellent example of well-structured Ruby code. It is hosted in the Rails Subversion repository (http://svn.rubyonrails.org/rails/ tools/capistrano/).

Of course, as Capistrano grows larger and becomes more general, some people just want a simple deployment tool. The Ruby Hit Squad released Vlad the Deployer (http://rubyhitsquad.com/Vlad_the_Deployer.html) as a reaction against Capistrano's complexity. It does one thing: application deployment. It uses native programs (ssh and rsync), as opposed to Capistrano, which depends on the Net::SSH library.

Because Vlad is focused on deployment only, the configuration file can be simpler. It defaults to one server; Capistrano assumes a large setup—the default deployment tasks assume separate web, app, and db roles. Either solution works well; generally, Vlad is easier to get started with, and Capistrano will be more flexible for large projects or those with unusual requirements.

Another powerful tool for software development, especially in large teams, is continuous integration. As a principle, continuous integration comes from the Extreme Programming discipline. It usually involves a build/test process that hap-pens either just before or just after each version control commit. If tests fail, an email is typically sent to the entire team, shaming the offending developer and providing an incentive to fix the code.

The most popular continuous integration framework is CruiseControl, which started as a Java project. It has since been ported to .NET and Ruby. ThoughtWorks maintains the Ruby port, CruiseControl.rb (http://cruisecontrolrb.thoughtworks.com/). It runs in the background and monitors the repository every 30 seconds for commits (the interval is configurable). When a new version is detected, it checks it out into a working directory and runs the tests with Rake. If there are failures or errors, a failure email is sent out. (Likewise, if the build was broken but is now fixed, a "fixed" email is sent.) CruiseControl.rb also provides a neat web interface to view test progress and results for the latest and previous builds.

Closely related is the ZenTest suite of tools by Ryan Davis.[93] ZenTest consists of five tools that help with test coverage, especially under Rails applications. The documentation tells the full story, but the most compelling part of this suite is autotest. This allows an even shorter cycle time than continuous integration tools. Although the method is similar to continuous integration, the AutoTest tools are used more for development (to shorten the cycles between writing code and testing it) than for continuous integration (which is more of a safety net to prevent obviously bad code from being deployed).

AutoTest sits in the background and watches the files in a Rails project. When any file is changed, AutoTest runs the appropriate tests immediately. It is pretty smart about which tests need to be run, and even watches test fixtures and other dependencies for changes. If you follow the test-driven development methodology, running AutoTest is a great way to force yourself to stay green. Get started with the following:

	$ sudo gem install ZenTest
	$ cd my_rails_app
	$ autotest -rails


[89] A forward proxy sits infront of users and accelerates content that those users request. A reverse proxy sits in front of web servers andaccelerates the content requested of that server. A proxy balancer is a reverse proxy that balances requests among its member servers.

[91] See http://www.die.net/musings/page_load_time/ for a full explanation.